首页 > 解决方案 > 为什么这是更新状态的有效方法?

问题描述

在 React文档中,它提到不应直接从当前状态计算下一个状态。这是因为状态更新是异步的,所以你不能保证你使用的是正确的状态值。

但是,在官方教程中,你会看到这个功能:

handleClick(i) {
    const history = this.state.history.slice(0, this.state.stepNumber + 1);
//  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    const current = history[history.length - 1];
    const squares = current.squares.slice();

    if (calculateWinner(squares) || squares[i]) {
      return;
    }

    squares[i] = this.state.xIsNext ? "X" : "O";

    this.setState({
      history: history.concat([
        {
          squares: squares
        }
      ]),
      stepNumber: history.length,
      xIsNext: !this.state.xIsNext
   });
}

您可以看到该变量historystate.history和的函数state.stepNumber。这与文档中提到的内容不矛盾,还是我遗漏了什么?

标签: javascriptreactjs

解决方案


在我看来,人们对此有点过于教条,但已经有足够的困难来追踪可能是合理的错误。最终,您必须知道为什么推荐它,以便知道特殊情况下是否可以。

为什么推荐它?

状态更新是异步的并且可以成批的,如果您多次更新状态并且您的一个或多个更新是基于以前的值,您可能会使用陈旧的值。在功能组件中,您面临与陈旧闭包相同的风险。

状态应该更新 5 次但只增加一次的示例:

功能组件示例:

const {useState} = React;

const Example = () => {
  const [value, setValue] = useState(0);
  
  const onClick = () => {
    [1,2,3,4,5].forEach(() => {
      console.log('update');
      setValue(value + 1);
    });
  }
   
  return (
    <div>
      <button onClick={onClick}>Update 5 times</button>
      <div>Count: {value}</div>
    </div>
  )
}

ReactDOM.render(<Example />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="root"></div>

类组件示例:

const {useState, useEffect} = React;

class Example extends React.Component {
  state = {
    count: 0
  }
  
  onClick = () => {
    [1,2,3,4,5].forEach(() => {
      this.setState({count: this.state.count + 1});
    });
  }

  render() {
    return (
      <div>
        <button onClick={this.onClick}>Update 5 times</button>
        <div>Count: {this.state.count}</div>
      </div>
    ); 
  }
}

ReactDOM.render(<Example />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root"/>

可以使用基于先前状态的正常状态更新吗?

这取决于您的用例。如果您绝对确定您只会更新一次状态,那么从技术上讲它是安全的。问题是,虽然今天它可能是安全的,但明天你或其他开发人员可能会在不知不觉中改变它......

归根结底,我认为您必须问自己:“我是否从不使用功能更新中获得任何额外的好处?”,如果是这样,那么了解未来错误的风险并采取行动(您可能应该记录它也很严重)。但几乎每次,答案都是使用功能更新


推荐阅读