为什么react setState方法是不可变的?

时间:2017-09-15 06:15:06

标签: javascript reactjs immutability difference setstate

以下来自React教程:

const squares = this.state.squares.slice();
squares[i] = 'X';
this.setState({squares: squares});

此代码更改已复制state.squares并将其分配给原始state.squares。最后,这会更改原始state.squares,所以我认为这与可变代码没有区别,如下所示:

this.state.squares[i] = 'X';

有什么不同吗?

4 个答案:

答案 0 :(得分:0)

你可以这样做,但你不应该这样做,背后的原因是,如果你使用

this.state.squares[i] = 'X';

它将被下一个

覆盖
this.setState({squares: squares});

因此,您的应用将无法获得准确的数据。

来自Doc:

  

不要直接改变this.state,因为之后调用setState()可能   替换你所做的突变。把它当作状态对待   不可变的。

https://facebook.github.io/react/docs/react-component.html#state

中查看详情

答案 1 :(得分:0)

此代码是不可变的,因为使用了slice()方法。如果您尝试:

someState = {squares: [1,2,3,4,5]}
squares = someState.squares.slice()

您将获得由slice()方法创建的新数组。

您可以这样测试:

squares = someState.squares.slice()
squares2 = someState.squares
squares[0] = 9    // doesn't change someState
squares2[1] = 9   // changes someState
someState.squares // [1,9,3,4,5] - as I said

如果你对this.setState({squares: squares});有疑问 - 是的,当然在运行之后你有了新的状态,但实际上这个状态不是修改旧状态对象,而是从旧部件创建的新对象。所以,如果你尝试:

oldState = this.state
this.setState({squares: squares})

您会看到新状态与保存旧状态不同:

this.state == oldState //false

如果this.state.squares[i] = 'X'; oldState也会被修改,这正是我们所说的可变性。旧状态的所有复制部分都随之改变,这会导致许多问题。

答案 2 :(得分:0)

我也很想知道这个问题。但我发现答案并不令人满意。所以这是我的看法

答案实际上是在doc本身中写的 http://reactjs.org/docs/state-and-lifecycle.html#do-not-modify-state-directly

首先,setState()触发render()

第二个原因,状态更改在React中是异步的,因此您可能还有一些其他组件在场景后面改变状态,而您仍然指的是旧的未更改状态,这会导致错误的状态值

答案 3 :(得分:0)

请勿直接更改状态,这就是医生所说的。

我正在编写一个待办事项列表,并犯了直接改变状态的相同错误,但是在我的情况下,我使用的是钩子。我不明白为什么在运行setState时屏幕不重新渲染。状态确实发生了突变(由console.log确认),甚至useEffect都因为它检测到更新的依赖关系而运行。

扩展Purecomponent的反应类也具有相同的行为。有趣的是,如果我使用扩展React.Component的类并使用this.setState函数,则应用程序确实会重新渲染屏幕。

经过询问和学习后,事实证明我需要将状态视为不变的。

此代码: var newwrongArr = this.state.arr; 不复制任何内容,它仅引用值,证明是,如果您对newwrongArr进行了变异,则状态也会发生变异。

如果要复制,代码应为:

var newArr = [...this.state.arr]; //the three dots are spread operator

或其他一些功能,例如Object.assign().

我的结论是,如果我们突变newwrongArrsetStatearr(newwrongArr),我认为React钩子将决定不需要重新渲染,因为它认为newwrongArr与state的值相同(尽管状态发生了变化,但不会发生重新呈现)。但是,如果我们要使用点差运算符复制值,则setState将考虑需要重新渲染,这是预期结果。

很抱歉,答案很长。