基本上,这个问题归结为React如何进行对帐。
组件更新时,实例保持不变,因此在渲染之间保持状态。React更新基础组件实例的道具以匹配新元素
假设我们有这个示例应用程序:
<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在我们的例子中,除了prop
,没有其他prop),并且可以通过重新计算其自身的状态来处理该状态。
由于我们的错误边界正在被重用,尽管它的状态无法更改,但它永远不会重新呈现其父级路由的新子级。
React为此隐藏了一个窍门,我只在它的博客上明确看到过它:
为了在移动到另一个项目时重置值(如在密码管理器方案中一样),我们可以使用称为key的特殊React属性。更改键后,React将
创建一个新的组件实例,而不是更新当前实例 。(…)在大多数情况下,这是处理需要重置的状态的最佳方法。
布莱恩·沃恩(Brian Vaughn)的错误绑定程序包中的一个相关问题首次向我暗示了这一点:
我建议重设此错误边界的方法(如果您确实想消除错误)将只是使用新的键值将其清除。(…)这将告诉React抛出前一个实例(带有错误状态),并用一个新实例替换它。
使用
keys
的替代方法是实现暴露一些可以在外部调用的钩子,或者通过尝试检查
children属性的更改来实现,这很困难。像这样的东西可以工作(演示):
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道具即可:-)



