我正在做这样的事情并想知道是否应该完全避免或接受。
因为将状态视为不可变状态会很复杂。
第一个版本是我通常做的
render() {
var { blogs } = this.state
var blogNodes = blogs.map((blog, i) => {
return (
<div>
{blog.name}
<Checkbox
checked={blog.checked}
onChange={
(e, {name, value, checked}) => {
blog.checked = checked
this.setState({blogs})
}
}
/>
</div>
)
})
} ,
第二个版本似乎是更正确的版本
render() {
var { blogs } = this.state
var blogNodes = blogs.map((blog, i) => {
return (
<div>
{blog.name}
<Checkbox
checked={blog.checked}
onChange={
(e, {name, value, checked}) => {
blog.checked = checked
var newState = update(this.state, {
blogs: {
i: {
$set: {
checked: checked
}
}
}
})
this.setState(newState)
}
}
/>
</div>
)
})
}
将反应状态视为不可变状态还是仅仅出于性能原因,是否绝对必要?
如果我必须将它视为不可变的,那么上面的第二个版本是否有更简单的方法? 当我们手头有索引(i)时,会更烦人。
答案 0 :(得分:1)
是否绝对必须保持组件状态不变?不,但重要的是要了解你为什么要这样做,特别是如果你在你的州树中嵌套(就像你的例子),这就是原因
当所述组件的状态(或道具)更新时,React更新组件,并且有关react的最佳部分是,您可以使用shouldComponentUpdate()生命周期事件对此更新进行TOTAL控制,所以..如果你正在改变你的状态对象,然后你将不得不做一些被称为深度资产检查的东西,以确定状态何时更新,当状态对象内部有更多嵌套时,这会变得更糟,
现在想象一下将状态保持为不可变对象,并最终得到这个明确且易于预测的漂亮状态对象,并且可以相应地优化组件以获得更好的性能......
其次,默认情况下做出反应,不要进行深度资产检查以查看状态或道具是否更新,这样你就可以听到他们告诉人们不要像其他人提到的那样改变状态,
现在要实现任何反应组件,请记住,保持状态最小是您可以获得的最佳React实践,因此最好只为组件提供渲染所需的值。
onChange(event, i) {
const target = event.target;
const value = target.type === 'checkbox' ? target.checked : target.value;
this.props.handleChange(this.props.blog, value)
}
render() {
var { blog } = this.state
return (
<div>
{blog.name}
<Checkbox
checked={blog.checked}
onChange={this.onChange}
/>
</div>
)
}
然后在您的父博客组件
中handleChange(blog, value) {
this.setState({
blogs: [
...blogs,
{...blog, selected: value}
]
})
}
答案 1 :(得分:0)
将反应状态视为不可变状态是否绝对必要?
取决于“绝对必要”的意思,但我认为如果the authors straight up tell you it's "wrong",在React中改变状态是一个非常糟糕的想法是安全的。如果你继续这样做的话,你会用脚射击自己。性能调优是一个原因,但另一个原因是,如果您不遵循React的API规则,例如无意中覆盖数据或以难以调试的方式破坏渲染,您将获得不可预测的行为。
React就是一个可预测的渲染周期:使用setState()
进行状态更改,这将在未来的某个时刻以最新状态触发render()
。
你的第二个例子仍有问题。首先,您仍然通过设置blog
来改变状态blog.checked = true
。其次,您正在用newState
替换整个状态。这是一个问题的处方,因为setState()
只有安排一个补丁,所以你应该只替换你正在改变的道具 - setState({blogs})
在你的情况下 - - 或者您可能与其他setState()
的来电冲突。最后,如果您正在访问当前state
,那么您应该使用回调表单(second example)来确保您正在使用的状态实际上是完全最新版本。
使用ES6对象传播你可以这样做:
this.setState((prevState, props) => {
const {blogs} = this.state;
return {
blogs: [
...blogs.slice(0, i),
{ ...blogs[i], selected: true }
...blogs.slice(i)
]
};
});
或者使用map()
只用索引替换一个元素:
this.setState((prevState, props) => {
const {blogs} = this.state;
return {
blogs: blogs.map(
(blog, index) => index == i ? { ...blog, selected: true } : blog
)
};
});