我应该使用forceUpdate()还是找到另一种方法来重新呈现React组件

时间:2016-10-11 15:02:02

标签: reactjs ecmascript-6 jsx axios

我有这个组件,我想在api电话后重新投降。我无法弄清楚为什么在api调用getWinks之后,winks-count会更新但不会在视图上更新,除非我刷新。我不应该使用this.forceUpdate()。请提出建议,欢迎任何批评。

export default class Winks extends Component {
  constructor (props) {
    super(props)
    this.insertDecimal = this.insertDecimal.bind(this)
    this.state = ({
      user:cookie.load('user',
    )})
    console.log(this.state)
    this.httpHandler = axios.create({
      baseURL: 'localhost:3000',
      headers: {
        'Authorization': this.state.user.token
      }
    })
  }

  insertDecimal(num) {
     var num = (num / 100).toFixed(2);
     return '$' + num
  }
 getWinks (itemId) {
   this.httpHandler.post("/users/" + this.state.user.id + "/winks", {
      user_id:this.state.user.id,
      wink: {
        product_id:itemId
      }
   }).then(function (response){
     this.forceUpdate()
   }.bind(this))
 }

  render () {
    var listItems = this.props.products.map(function(item, index,) {
      var wink = item.attributes
      if (index % 5 ===0) {
        return (
          <Col lg={2} md={4} sm={4} xs={6}>
            <div className="item">
              <img className='img-responsive' src={wink["image-url"]}></img>
              <div className="item-meta">
                <span className="name">{wink.name}</span>
                <span className="site"> Bloomingdales.com</span>
                <div className="rate">
                  <span className="old">{this.insertDecimal(wink.price)}</span>
                  <span className="new">{this.insertDecimal(wink["sale-price"])}</span>
                </div>
                <div className="like">
                  <i onClick={()=>this.getWinks(item.id)} className="fa fa-heart"></i>
                  <span>{wink["winks-count"]}</span>
                </div>
              </div>
            </div>
          </Col>
        )
      }
      else {
        return (
          <Col lg={2} md={4} sm={4} xs={6}>
            <div className="item">
              <img className='img-responsive' src={wink["image-url"]}></img>
              <div className="item-meta">
                <span className="name">{wink.name}</span>
                <span className="site"> Bloomingdales.com</span>
                <div className="rate">
                  <span className="old">{this.insertDecimal(wink.price)}</span>
                  <span className="new">{this.insertDecimal(wink["sale-price"])}</span>
                </div>
                <div className="like">
                  <i onClick={()=>this.getWinks(item.id)} className="fa fa-heart"></i>
                  <span>{wink["winks-count"]}</span>
                </div>
              </div>
            </div>
          </Col>
        )
      }
    }.bind(this));
    return (
        <Row className="item-row">
          {listItems}
        </Row>
    )
  }
}

父组件:

export default class AllItems extends Component {
  constructor () {
    super()
    this.state=({ user: cookie.load('user')})
    this.httpHandler = axios.create({
      baseURL: 'localhost:3000',
      headers: {
        'Authorization': this.state.user.token
      }
    })
  }

  componentWillMount() {
    this.httpHandler('/products/')
    .then(function (response) {
      this.setState({ winks: response.data.data})
    }.bind(this))
  }
  render() {

      return (
        <Grid>
          <div className="item-wrapper">
            <Row>
              <h1 className="text-center">All Items</h1>
            </Row>
            <Row>
              <Col xs={2}>
                <div className="item-sidebar-wrapper">
                  <div className="sort">
                    <Sort />
                  </div>
                  <div className="category">
                    <Category />
                  </div>
                  <div className="price">
                    <Price />
                  </div>
                  <div className="size">
                    <Size />
                  </div>
                  <div className="color">
                    <Color />
                  </div>
                  <div className="brand">
                    <Brand />
                  </div>
                  <div className="stores">
                    <Stores />
                  </div>
                </div>
              </Col>
              <Col xs={10}>
                <Winks products={this.state.winks} />
              </Col>
            </Row>
          </div>
        </Grid>
      )

4 个答案:

答案 0 :(得分:1)

通常,您永远不必使用forceUpdate()。相反,您应该使用this.setState()来更新数据,因为它会使您的组件使用新数据自动重新渲染。

从您的示例中不清楚,但假设response方法中的getWinks()参数包含更新的产品,则应使用它来更新状态。

但是,由于您使用道具获取父级的初始产品,因此您需要将更新的产品传递回父级并让它运行this.setState({ products })(这将触发重新渲染,从而导致您显示的用新数据重新渲染的组件。

答案 1 :(得分:0)

使用state。比如说,使用状态loader,当您调用true时,它应设置为httpHandler,并在异步操作完成时设置为false。这样,更改状态将重新呈现组件而不包含任何forceupdate()

像这样。

getWinks (itemId) {
   this.setState({loading: true})
   this.httpHandler.post("/users/" + this.state.user.id + "/winks", {
      user_id:this.state.user.id,
      wink: {
        product_id:itemId
      }
   }).then(function (response){
     this.setState({loading: false})
   }.bind(this)) 
}

答案 2 :(得分:0)

您的组件不会重新渲染,因为您没有更改其状态或道具,因此它没有任何更新,这只是反应的工作方式。

在您的代码中,您正在发送POST请求,但您没有对响应做任何事情。你能解释一下这个要求是做什么的吗?

答案 3 :(得分:0)

您的组件是propsstate的功能。因此,无论何时更改,您的组件都会再次呈现。

如果传递给您组件的stateprops从对该组件或任何父组件的调用setState(...)变为,则您的组件将再次呈现。因此,唯一需要使用forceupdate()的时间是当您需要将该组件呈现为其他功能的时候。

例如,假设您有一个Timer组件正在传递属性elapsedrunningSinceTimer组件将根据elapsedrunningSinceDate.now()计算显示给用户的时间。但是,除非用户单击“开始”或“停止”按钮,否则elapsedrunningSince不会更改。但是然后Timer组件将不会显示实时计时器,因为没有任何东西可以触发它的render函数。要解决此问题,您可以添加一个更新间隔,例如,每个forceupdate()会调用50 ms