我应该使用 forceUpdate() 还是寻找另一种方法来重新渲染 React 组件

Should i be using forceUpdate() or finding another way to rerender React component

我有这个组件,我想在 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>
      )

使用 state。比如说,使用状态 loader,当您调用 httpHandler 时它应该设置为 true,当异步操作完成时它应该设置为 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)) 
}

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

从你的例子看不清楚,但假设getWinks()方法中的response参数包含更新的产品,它应该用于更新状态。

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

你的组件不会重新渲染,因为你没有改变它的状态或道具,所以它没有任何要更新的东西,这就是反应的工作原理。

在您的代码中,您发送了 POST 请求,但您没有对响应执行任何操作。您能解释一下这个请求的作用吗?

您的组件是 propsstate 的函数。因此,只要它们发生变化,您的组件就会再次呈现。

如果传递给组件的 stateprops 从调用组件或任何父组件上的 setState(...) 更改,则您的组件将再次呈现。因此,您唯一会使用 forceupdate() 的情况是当您需要组件作为其他功能呈现时。

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