我正在做官方的ReactJs教程,我开始对不变性的含义和应用感到困惑。
我认为的方式的一个例子。想象一下,我在构造函数this.state = { dog: some data}
中有一个对象,然后我调用一个设置this.setState = {dog: another data}
的handleClick函数。由于我使用setState
来更新值,旧引用仍然是不可变的,我可以知道发生了什么变化。
但是在教程中,当他们复制" square"状态.slice()
不更改原始数组然后应用setState
新值,我感到困惑。
为什么他们需要复制数组,他们不能只在setState
中引用它并改变那里的东西?原始参考文献仍然可追溯......
编辑:
@FelixKling这里:
class Board extends React.Component {
constructor() {
super();
this.state = {
squares: Array(9).fill(null),
};
}
handleClick(i) {
const squares = this.state.squares.slice();
squares[i] = 'X';
this.setState({squares: squares});
}
}
他们不能把它放在setState
里面,而不是复制初始数组吗?
答案 0 :(得分:2)
这是一篇非常好的文章,有助于解释为什么不变性很重要:http://reactkungfu.com/2015/08/pros-and-cons-of-using-immutability-with-react-js/
事实上,React.js不需要了解究竟改变了什么。它需要知道的是状态是否完全改变。
虽然不可变性不能为究竟发生了什么改变问题提供更简单的答案,但它为提供了一个很好的答案,它是否完全改变了问题。
反应,顾名思义'反应'改变状态,并在状态改变时重新渲染组件。因此,对于React来说,知道状态是否变化很重要,遗憾的是,变异对象会使得比较变得困难。
考虑这个例子:
var a = 6; // numbers are primatives in javascript and compare by value
var b = 6;
var c = a; // 6
// in this case
a === b // true
b === c // true, 6
但你不能通过引用比较对象来做同样的事情,也就是说它们指向内存中的同一点。
var objA = { name: 'Sally' };
var objB = { name: 'Sally' };
var objC = objA;
// these are not the same object
objA.name === objB.name // true, 'Sally'
objA === objB // false, they reference different objects even though the keys and values are the same
objA === objC // true, they reference the same point in memory
当您尝试修改值时,更容易说明React中出现的问题。
让我们再次以我们的数字为例进行一些修改:
c = 14;
a === b // true, still 6, the value of 'a' is still 6
a === c // false, 6 ≠ 14
这意味着,我们已经改变了c的价值,它现在应该是不同的。我们现在修改我们的对象。
objA.age = 30; // give objA an age property
objB.age = 35; // give objB an age property
objC.age = 40; // give objC an age property, actually changes objA
// now try equality
objA === objB // false, we already know this
objA.age === objB.age // false, as expected
objA.age === objC.age // true, possibly unexpected as it looks like we are comparing 30 to 40, but in fact our change to objC modified objA
objA === objC // true both have age set to 40
因此,如果我们每次都给React一个新的状态,而不是改变它,那么它是否应该更容易知道它是否应该重新渲染。
你可能想知道,为什么反应并不只是存储状态的副本并将其与变异状态进行比较。也许你并不想知道这一点,但似乎这是React / Redux可以处理的东西,然后我们可以自由地改变状态,让我们更容易。
事实证明,比较两个对象是一项非常密集的任务,首先你必须确保它们都具有相同的键,并且这些键具有相同的值 - 看起来并不难 - 但是然后你意识到对象可以包含许多其他嵌套对象,这个比较变得递归,检查每个嵌套对象。
传递一个新的状态要容易得多,以便React可以立即告诉它已经改变了。
除此之外,生成新状态还允许您定时旅行。通过跟踪和存储以前的状态,如果你选择。
答案 1 :(得分:0)
在教程中,他们详细说明了不变性的重要性: https://facebook.github.io/react/tutorial/tutorial.html#why-immutability-is-important
您还可以在此处阅读很多关于不变性的内容:https://facebook.github.io/immutable-js/
Immutable JS是Facebook为对象Immutability创建的库
TLDR链接:跟踪更改基本上更容易,更容易确定何时重新渲染。
关于评论的编辑:
所以你是正确的this.setState
确实更新了对象而不是改变对象。
在这个例子中,我们创建一个副本而不是变异。
handleClick(i) {
const squares = this.state.squares.slice();
squares[i] = this.state.xIsNext ? 'X' : 'O';
this.setState({
squares: squares,
});
}
在这个例子中,我们改变而不是创建副本
handleClick(i) {
this.state.squares[i] = this.state.xIsNext ? 'X' : 'O';
this.setState({
squares: squares,
});
}
对于我们没有变异的第一个例子,当React在this.setState被调用并且到达shouldComponentUpdate
之后运行其生命周期事件时,这将是会发生什么
shouldComponentUpdate(nextProps, nextState) {
// this will return true and trigger an update
return this.state.squares !== nextState;
}
对于第二个例子,我们做了变异的地方,接下来会发生什么:
shouldComponentUpdate(nextProps, nextState) {
// this will return false and will not trigger an update
return this.state.squares !== nextState;
}
现在,即使我们已经改变了状态,因为我们当前的变异状态与我们的下一个状态(在this.setState中设置)相同,我们的react组件将不会更新。