使用React Error Boundaries打破浏览器导航

Und*_*per 17 browser-history reactjs react-router

当我们的React 16代码库中出现错误时,它会被我们的顶级错误边界捕获.ErrorBoundary发生这种情况时,组件会愉快地呈现错误页面.

ErrorBoundary所在的位置

   return (
     <Provider store={configureStore()}>
       <ErrorBoundary>
         <Router history={browserHistory}>{routes}</Router>
       </ErrorBoundary>
     </Provider>
   )
Run Code Online (Sandbox Code Playgroud)

但是,使用浏览器后退按钮(单击一次)导航回来时,URL会在地址中更改,但页面不会更新.

我已经尝试将错误边界向下移动到组件树,但此问题仍然存在.

关于这个问题在哪里的任何线索?

jda*_*ies 31

op现在可能已经找到了一个解决方案,但是为了其他任何有这个问题的人的利益,我将解释为什么我认为它正在发生以及可以做些什么来解决它.

这可能是由于ErrorBoundary中的条件呈现呈现错误消息,即使历史记录已更改.

虽然上面没有显示,但ErrorBoundary中的render方法可能类似于:

render() {
  if (this.state.hasError) {
    return <h1>An error has occurred.</h1>
  }

  return this.props.children;
}
Run Code Online (Sandbox Code Playgroud)

其中hasError在componentDidCatch生命周期方法中设置.

一旦设置了ErrorBoundary中的状态,它将始终呈现错误消息,直到状态发生变化(上例中的hasError为false).即使历史记录发生更改,也不会呈现子组件(在这种情况下为路由器组件).

要解决此问题,请通过包装ErrorBoundary的导出来使用react-router withRouter更高阶组件,以通过props访问历史记录:

export default withRouter(ErrorBoundary);
Run Code Online (Sandbox Code Playgroud)

在ErrorBoundary构造函数中,从props中检索历史记录并设置处理程序以使用history.listen监听对当前位置的更改.当位置发生变化(单击后退按钮等)时,如果组件处于错误状态,则会清除该位置,以便再次渲染子项.

const { history } = this.props;

history.listen((location, action) => {
  if (this.state.hasError) {
    this.setState({
      hasError: false,
    });
  }
});
Run Code Online (Sandbox Code Playgroud)

  • React-router v6 删除了这个 hoc xx (3认同)

小智 8

要添加到上面 jdavies 的回答中,请确保在 a componentDidMountor 中注册历史监听器useEffect[]用于表示它没有依赖项),并在 a or return 语句中取消注册,否则您可能会遇到在未安装的组件中调用的问题.componentWillUnmountuseEffectsetState

例子:

  componentDidMount() {
    this.unlisten = this.props.history.listen((location, action) => {
      if (this.state.hasError) {
        this.setState({ hasError: false });
      }
    });
  }

  componentWillUnmount() {
    this.unlisten();
  }
Run Code Online (Sandbox Code Playgroud)