错误边界会禁用交换机内部的路由 [英] Error Boundaries disables routing inside of a Switch

查看:88
本文介绍了错误边界会禁用交换机内部的路由的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

对于很长时间在遇到错误边界后一直试图使路由在我们的应用程序中工作,但是直到今天我才发现看起来与周围的许多示例相同的代码有一个重要区别:路由由<$包裹c $ c>切换。如果启用了此简单更改,就足以停止路由工作。 演示

For a long time I have been trying to get routing to work in our app after an error boundary has been hit, but only today did I find the code that was seemingly identical to the many examples lying around had one important difference: the routes were wrapped by a Switch. This simple change is enough to stop routing from working, if enabled. Demo

使用以下代码段。如果删除 Switch 位,即使每个组件都应该失败,此方法也可以正常工作,但如果由开关包装,则不会。我想知道为什么。

Take the following snippet. If I remove the Switch bit, this works fine even if each component should fail, but not if wrapped by the switch. I would like to know why.

<div style={{ backgroundColor: "#ffc993", height: "150px" }}>
<Switch>
  <Route
    path="/"
    exact
    render={() => (
      <ErrorBoundary>
        <MyComponent1 title="Component 1" />
      </ErrorBoundary>
    )}
  />
  <Route
    path="/comp1"
    render={() => (
      <ErrorBoundary>
        <MyComponent1 title="Component 1 Again" />
      </ErrorBoundary>
    )}
  />
  <Route
    path="/comp2"
    render={() => (
      <ErrorBoundary>
        <MyComponent2 title="Component 2" />
      </ErrorBoundary>
    )}
  />
</Switch>


推荐答案

基本上,这个问题归结为React的工作方式< a href = https://reactjs.org/docs/reconciliation.html#component-elements-of-the-same-type rel = noreferrer>和解。

Basically, this problem boils down to how React does reconciliation.


当组件更新时,实例保持不变,因此在渲染器之间保持状态。 React更新基础组件实例的道具以匹配新元素

When a component updates, the instance stays the same, so that state is maintained across renders. React updates the props of the underlying component instance to match the new element

说我们有这个示例应用程序:

Say we have this example app:

<App>
  <Switch>
    <Route path="a" component={Foo}/>
    <Route path="b" component={Foo}/>
  </Switch>
</App> 

这有点不直观,将重用 Foo 两条路线! < Switch> 将始终返回第一个匹配的元素,因此基本上,当React渲染时,这等效于树< App>< Foo />< / App> 表示路径 a,而< App>< Foo />< / App> 路径 b。如果Foo是具有状态的组件,则意味着状态得以保留,因为实例只是通过了新的道具(在我们的例子中,除了 children 之外,没有其他道具)

This will, somewhat unintuitively, reuse the same instance of Foo for both routes! A <Switch> will always return the first matched element, so basically when React renders this is equivalent of the tree <App><Foo/></App> for path "a" and <App><Foo/></App> for path "b". If Foo is a component with state, that means that state is kept, as the instance is just passed new props (for which there are none, except children, in our case), and is expected to handle this by recomputing its own state.

由于我们的错误边界正在被重用,而它的状态无法改变,因此它永远不会重新渲染其父路线的新子级。

As our error boundary is being reused, while it has state that has no way of changing, it will never re-render the new children of its parent route.

为此,React隐瞒了一个窍门,我只在其博客上明确看到过它:

React has one trick hidden up its sleeve for this, which I have only seen explicitly documented on its blog:

为了在移动到另一个项目时重置值(如在密码管理器方案中一样),我们可以使用称为key的特殊React属性。更改键后,React将创建一个新的组件实例,而不是更新当前的实例
(...)在大多数情况下,这是处理需要重置状态的最佳方法。

In order to reset the value when moving to a different item (as in our password manager scenario), we can use the special React attribute called key. When a key changes, React will create a new component instance rather than update the current one. (...) In most cases, this is the best way to handle state that needs to be reset.

布莱恩·沃恩(Brian Vaughn)错误的相关问题首先在相关问题中得到了提示绑定包

I was first hinted to this by a somewhat related issue on Brian Vaughn's error bondary package:


我建议重置此错误边界的方式(如果您真的想消除错误)只需使用新的键值将其清除即可。 (...)这将告诉React丢弃前一个实例(具有错误状态),并用新实例替换它。

The way I would recommend resetting this error boundary (if you really want to blow away the error) would be to just clear it out using a new key value. (...) This will tell React to throw out the previous instance (with its error state) and replace it with a new instance.

使用 key s的替代方法是要么公开一些可以在外部调用的钩子,要么尝试检查 children 用于更改的属性,这很难。这样的事情可能会起作用(演示):

The alternative to using keys would be to implement either exposing some hook that could be called externally or by trying to inspect the children property for change, which is hard. Something like this could work (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 });
   }

但是这样做比较麻烦,而且容易出错,所以烦恼:坚持添加道具:-)

But it's more work and much more error prone, so why bother: just stick to adding a key prop :-)

这篇关于错误边界会禁用交换机内部的路由的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆