直接改变状态和 forceUpdate() 与 setState 的缺点

IT技术 javascript reactjs
2021-05-04 16:55:40

React 文档说Never mutate this.state directly, as calling setState() afterwards may replace the mutation you made. Treat this.state as if it were immutable...但是当我根本不使用 setState() 时,这不是问题。

我能想到的唯一缺点是:

  • 无法使用shouldComponentUpdate/ componentWillUpdate/componentDidUpdate比较新旧状态。

  • 可能会使其他工作人员的可维护性变得更加困难。因为这不是做事的标准方式。

但是不使用 setState() 和直接改变 state是否还有其他缺点?


编辑:我已经删除了我被这个想法所吸引的理由。我知道这是一种反模式,我知道这可能不是最好的方法。但这个问题完全是关于“为什么”。

EDIT2:另外这里的关键词是other... are there any other disadvantages ...

1个回答

你不应该直接改变状态。setState 的异步性质有办法绕过它。setState提供了一个callback你可以使用的。

forceUpdate 也完全绕过了shouldComponentUpdate这不是一个好的模式,尤其是在使用它对React.PureComponent你的props进行浅层比较时。

此外,您不应该使用反模式,而是尝试按照文档建议的正确方法解决您的问题

使用setState此模式可能会松散的另一个优点是比较您previouscurrentState自从您创建对象以来的对象,mutable特别是在您的生命周期函数中

直接设置状态的一个缺点是 React 的生命周期方法 - shouldComponentUpdate(), componentWillUpdate(), componentDidUpdate()- 依赖于被调用的状态转换 setState()如果直接更改状态并setState()使用空对象调用,则无法再实现这些方法。

此外,您可能个人知道您的代码与 React 交互的方式是这些覆盖或其他问题不会发生,但您正在创造一种情况,其他开发人员或未来的更新可能会突然发现自己遇到奇怪或微妙的问题,当他们开始遵循正确的方法

使用 setState 改变状态

class App extends React.Component {
  state =  {
      counter: 0
  }
  updateCounter = () => {
    this.setState(prevState => ({counter: prevState.counter + 1}));
  }
  componentWillUpdate(nextProps, nextState){
    console.log(this.state.counter === nextState.counter);
  }
  
  componentDidUpdate(prevProps, prevState) {
     console.log(this.state.counter === prevState.counter);
  }
  render() {
      return (
        <div>
          {this.state.counter}
          <button onClick={this.updateCounter}>Increment</button>
        </div>
      )
  }
}

ReactDOM.render(<App/>, document.getElementById('app'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="app"></div>

直接改变状态

class App extends React.Component {
  state =  {
      counter: 0
  }
  updateCounter = () => {
    this.state.counter =  this.state.counter + 1;
    this.forceUpdate();
  }
  componentWillUpdate(nextProps, nextState){
    console.log(this.state.counter === nextState.counter);
  }
  
  componentDidUpdate(prevProps, prevState) {
     console.log(this.state.counter === prevState.counter);
  }
  render() {
      return (
        <div>
          {this.state.counter}
          <button onClick={this.updateCounter}>Increment</button>
        </div>
      )
  }
}

ReactDOM.render(<App/>, document.getElementById('app'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="app"></div>