实际上,为什么我不能直接修改组件的状态?

JavaScript React.js

2020-04-03

我知道,React教程和文档毫无疑问地警告,状态不应该直接变异,所有事情都应该通过setState

我想了解一下,为什么我不能直接更改状态,然后(在同一函数中)调用this.setState({})仅触发render

例如:以下代码似乎正常工作:

const React = require('react');

const App = React.createClass({
    getInitialState: function() {
        return {
            some: {
                rather: {
                    deeply: {
                        embedded: {
                            stuff: 1
                        }}}}};
    },
    updateCounter: function () {
        this.state.some.rather.deeply.embedded.stuff++;
        this.setState({}); // just to trigger the render ...
    },
    render: function() {
        return (
                <div>
                Counter value: {this.state.some.rather.deeply.embedded.stuff}
                <br></br>
                <button onClick={this.updateCounter}>inc</button>
                </div>
        );
    }
});

export default App;

I am all for following conventions but I would like to enhance my further understanding of how ReactJS actually works and what can go wrong or is it sub-optimal with the above code.

The notes under the this.setState documentation basically identify two gotchas:

  1. That if you mutate state directly and then subsequently call this.setState this may replace (overwrite?) the mutation you made. I don't see how this can happen in the above code.
  2. That setState may mutate this.state effectively in an asynchronous / deferred way and so when accessing this.state right after calling this.setState you are not guaranteed to access the final mutated state. I get that, by this is not an issue if this.setState is the last call of the update function.

第3975篇《实际上,为什么我不能直接修改组件的状态?》来自Winter(https://github.com/aiyld/aiyld.github.io)的站点

2个回答
2020.04.03

React文档setState对此有这样的说法:

切勿this.state直接进行突变,因为setState()随后的呼叫可能会取代您所做的突变。对待this.state就好像它是不可变的。

setState()不会立即变异,this.state但会创建待处理的状态转换。this.state调用此方法后进行访问可能会返回现有值。

无法保证对呼叫的同步操作,setState并且可以为提高性能而对呼叫进行批量处理。

setState()除非在中实现了条件渲染逻辑,否则它将始终触发重新渲染shouldComponentUpdate()如果正在使用可变对象,并且无法在中实现逻辑shouldComponentUpdate(),则setState()仅在新状态与先前状态不同时进行调用才能避免不必要的重新渲染。

基本上,如果this.state直接进行修改,则会造成一种情况,即这些修改可能会被覆盖。

与您的扩展问题1)和2)有关,setState()不是立即的。它根据其正在进行的状态对状态转换进行排队,该状态转换可能不包括对的直接更改this.state由于已排队而不是立即应用,因此完全有可能在两者之间进行某些修改,以使您的直接更改被覆盖。

如果没有别的,您可能会觉得更好,只是考虑将不直接修改this.state视为良好做法。您可能个人知道您的代码与React交互时不会发生这些覆盖或其他问题,但是您正在创建一种情况,其他开发人员或将来的更新可能突然发现自己遇到奇怪或微妙的问题。

JinJin 2020.04.03

我目前的理解是基于这个这个答案:

如果不使用 shouldComponentUpdate或任何其他生命周期方法(如componentWillReceivePropscomponentWillUpdatecomponentDidUpdate),您比较新旧道具/状态

然后

可以先进行突变state然后调用setState(),否则就不行了。

问题类别

JavaScript Ckeditor Python Webpack TypeScript Vue.js React.js ExpressJS KoaJS CSS Node.js HTML Django 单元测试 PHP Asp.net jQuery Bootstrap IOS Android