以下来自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';
有什么不同吗?
答案 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().
我的结论是,如果我们突变newwrongArr
和setStatearr(newwrongArr)
,我认为React钩子将决定不需要重新渲染,因为它认为newwrongArr
与state的值相同(尽管状态发生了变化,但不会发生重新呈现)。但是,如果我们要使用点差运算符复制值,则setState将考虑需要重新渲染,这是预期结果。
很抱歉,答案很长。