免责声明
React 中的嵌套状态是错误的设计
阅读this excellent answer。
这个答案背后的原因:
React 的 setState 只是一个内置的便利,但你很快就会意识到
它有它的极限。使用自定义属性和智能使用
forceUpdate 给你更多。
例如:
class MyClass extends React.Component {
myState = someObject
inputValue = 42
...
例如,MobX 完全抛弃状态并使用自定义的可观察属性。
Use Observables instead of state in React components.
还有另一种更短的方法可以更新任何嵌套属性。
this.setState(state => {
state.nested.flag = false
state.another.deep.prop = true
return state
})
单行
this.setState(state => (state.nested.flag = false, state))
注意:这里是Comma operator ~MDN,查看实际操作here (Sandbox)。
类似于(虽然这不会改变状态引用)
this.state.nested.flag = false
this.forceUpdate()
有关forceUpdate 和setState 在此上下文中的细微差别,请参阅链接的example 和sandbox。
这当然是在滥用一些核心原则,因为state 应该是只读的,但是由于您立即丢弃旧状态并用新状态替换它,所以完全可以。
警告
即使包含状态的组件将正确更新和重新渲染(except this gotcha),道具也将无法传播给孩子(见下方 Spymaster 的评论)。仅当您知道自己在做什么时才使用此技术。
例如,您可以传递一个已更改的扁平道具,该道具可以轻松更新和传递。
render(
//some complex render with your nested state
<ChildComponent complexNestedProp={this.state.nested} pleaseRerender={Math.random()}/>
)
现在即使 complexNestedProp 的参考没有改变 (shouldComponentUpdate)
this.props.complexNestedProp === nextProps.complexNestedProp
组件将在父组件更新时重新渲染,这是在父组件中调用this.setState 或this.forceUpdate 之后的情况。
使用嵌套状态并直接改变状态是危险的,因为不同的对象可能(有意或无意地)持有对状态的不同(旧)引用并且可能不一定知道何时更新(例如,当使用PureComponent 或如果shouldComponentUpdate 实现返回false)OR 旨在显示旧数据,如下例所示。
想象一个应该呈现历史数据的时间线,改变手下的数据会导致意想不到的行为,因为它也会改变以前的项目。
无论如何,您都可以看到 Nested PureChildClass 由于 props 无法传播而没有重新渲染。