基本上,这个问题归结为 React 是如何做的和解.
当组件更新时,实例保持不变,以便跨渲染保持状态。 React 更新底层组件实例的 props 以匹配新元素
假设我们有这个示例应用程序:
<App>
<Switch>
<Route path="a" component={Foo}/>
<Route path="b" component={Foo}/>
</Switch>
</App>
这将有点不直观地重用相同的实例Foo
两条路线! A<Switch>
将始终返回第一个匹配的元素,所以基本上当 React 渲染时,这相当于树<App><Foo/></App>
对于路径“a”和<App><Foo/></App>
对于路径“b”。如果 Foo 是一个具有状态的组件,则意味着状态被保留,因为实例刚刚传递了新的 props(除了children
,在我们的例子中),并期望通过重新计算自己的状态来处理这个问题。
由于我们的错误边界被重用,虽然它的状态无法更改,但它永远不会重新渲染其父路由的新子路由。
React 有一个隐藏的技巧,我只在它的博客上看到过它的明确记录:
为了在移动到不同的项目时重置值(如在我们的密码管理器场景中),我们可以使用名为 key 的特殊 React 属性。当某个键发生变化时,React 会创建一个新的组件实例而不是更新当前的组件实例。
(...) 在大多数情况下,这是处理需要重置的状态的最佳方法。
我首先被某种程度的暗示Brian Vaughn 错误债券包的相关问题:
我建议重置此错误边界的方法(如果您确实想消除错误)是使用新的键值将其清除。 (...) 这将告诉 React 丢弃之前的实例(及其错误状态)并用新实例替换它。
使用的替代方案key
的方法是公开一些可以从外部调用的钩子,或者尝试检查children
改变财产,这很难。像这样的东西可以工作(demo):
componentDidUpdate(prevProps, prevState, snapshot) {
const childNow = React.Children.only(this.props.children);
const childPrev = React.Children.only(prevProps.children);
if (childNow !== childPrev) {
this.setState({ errorInfo: null });
}
但这需要更多的工作并且更容易出错,所以为什么要费心:只需坚持添加一个key
道具:-)