我们正在讨论如何在React中更新嵌套状态。 国家应该是不可变的吗?优雅地更新状态的最佳做法是什么?
假设你的状态结构如下:
this.state = {
numberOfStudents: "3",
gradeLevel: "5",
students : [
{ id : "1234",
firstName: "John",
lastName: "Doe",
email: "johndoe@mail.com"
phoneNumer: "12345"
},
{ id : "56789",
firstName: "Jane",
lastName: "Doe",
email: "janedoe@mail.com"
phoneNumer: "56789"
},
{ id : "11111",
firstName: "Joe",
lastName: "Doe",
email: "joedoe@mail.com"
phoneNumer: "11111"
}
]
}
然后我们想要更新joe doe的电话号码。 我们有两种方法可以做到:
mutate state + force update to rerender
this.state.students[2].phoneNumber = "9999999";
this.forceUpdate();
mutate state + setState with mutated state
this.state.students[2].phoneNumber = "9999999";
this.setState({
students: this.state.students
});
Object.assign,这仍然会改变状态,因为newStudents只是对同一个对象的一个新引用this.state指向
const newStudents = Object.assign({}, this.state.students);
newStudents[2].phoneNumber = "9999999"
this.setState({
students: newStudents
});
更新immutability helper(https://facebook.github.io/react/docs/update.html)+ setState。如果我们在每个学生对象中都有address.street,address.city,address.zip并且想要更新街道,那么这会很快变得丑陋。
const newStudents = React.addons.update(this.state.students, {2: {phoneNumber: {$set:"9999999"}}});
this.setState({
students: newStudents
})
setState的react doc的最后一行声明:
不要直接改变this.state,因为之后调用setState()可能 替换你所做的突变。把它当作状态对待 不可改变的。 https://facebook.github.io/react/docs/react-component.html
文档声明我们不应该使用forceUpdate来重新渲染:
通常你应该尽量避免使用forceUpdate() 在this()中读取this.props和this.state。
为什么会这样,如果我们改变状态并在之后调用setState会发生什么?在什么情况下setState()会替换我们所做的突变?这是一个非常令人困惑的陈述。有人可以解释我们上面用于设置状态的每个场景的可能复杂性。
答案 0 :(得分:2)
您声明:
" Object.assign,这仍然会改变状态,因为newStudents只是对同一个对象的一个新引用this.state指向"
此声明不正确。
Object.assign
将传入其第一个参数的状态变为。由于您传入了一个空的对象文字({}
),因此您正在改变新的对象文字 和 而不是this.state
。
不可变状态的原理与函数式编程有关。
它在React中很有用,因为它为React提供了一种知道的方法 状态已经发生了变化,一个用例是有用的,可以优化组件应该重新渲染的时间
考虑具有嵌套对象的复杂状态的情况。 改变状态值会改变状态中属性的值,但不会改变对象的引用。
this.state = {nestObject:{nestedObj:{nestObj:'yes'}}};
// mutate state
this.state.nestObject.nestedObj.nestObj= 'no';
我们如何知道React是否应该重新渲染组件?
后两种方法可以替代吗?
通过创建一个新对象(以及一个新的引用),使用Object.assign
复制旧状态并对其进行变更,您可以操纵状态值并更改对象引用。
使用Immutable状态方法,我们可以通过简单地检查对象引用是否相等来知道状态是否已经改变。
考虑这个简单的例子:
this this.state = { someValue: 'test'}
var newState = Object.assign({}, this.state);
console.log(newState); // logs: Object {someValue: "test"]
console.log(this.state); // logs: Object {someValue: "test"]
// logs suggest the object are equal (in property and property value at least...
console.log(this.state === this.state); // logs: true
console.log(this.state === newState); // logs: false. Objects are
// pass-by-reference, the values stored
// stored in this.state AND newState
// are references. The strict equality
// shows that these references
// DON'T MATCH so we can see
// that an intent to modify
// state has been made