React 16コードベースでエラーがスローされると、トップレベルのエラー境界によってキャッチされます。これが発生すると、ErrorBoundary
コンポーネントはエラーページを適切にレンダリングします。
ErrorBoundaryが置かれている場所
return (
<Provider store={configureStore()}>
<ErrorBoundary>
<Router history={browserHistory}>{routes}</Router>
</ErrorBoundary>
</Provider>
)
ただし、ブラウザの戻るボタン(ワンクリック)を使用して戻ると、アドレスのURLは変更されますが、ページは更新されません。
エラー境界をコンポーネントツリーの下にシフトしようとしましたが、この問題は解決しません。
この問題がどこにあるかについての手がかりはありますか?
作戦はおそらく今までに解決策を見つけましたが、この問題を抱えている他の人のために、なぜそれが起こっていると思うのか、そしてそれを解決するために何ができるのかを説明します。
これは、履歴が変更されていても、エラーメッセージをレンダリングするErrorBoundaryの条件付きレンダリングが原因で発生している可能性があります。
上には示されていませんが、ErrorBoundaryのrenderメソッドはおそらく次のようになっています。
render() {
if (this.state.hasError) {
return <h1>An error has occurred.</h1>
}
return this.props.children;
}
componentDidCatch
ライフサイクルメソッドでhasErrorが設定されている場所。
ErrorBoundaryの状態が設定されると、状態が変化するまで常にエラーメッセージが表示されます(上記の例ではhasErrorがfalseになります)。履歴が変更されても、子コンポーネント(この場合はルーターコンポーネント)はレンダリングされません。
これを解決するには、errorBoundaryのエクスポートをラップして、小道具を介して履歴にアクセスできるようにすることで、react-router withRouter 高次コンポーネントを利用します。
export default withRouter(ErrorBoundary);
ErrorBoundaryコンストラクターで、小道具から履歴を取得し、 history.listen を使用して現在の場所への変更をリッスンするハンドラーを設定します。コンポーネントがエラー状態の場合に場所が変更されると(戻るボタンがクリックされるなど)、それはクリアされ、子を再度レンダリングできるようになります。
const { history } = this.props;
history.listen((location, action) => {
if (this.state.hasError) {
this.setState({
hasError: false,
});
}
});
上記のjdaviesの回答に追加するには、履歴リスナーをcomponentDidMount
またはuseEffect
に登録してください(依存関係がないことを示すために[]
を使用)。nregistercomponentWillUnmount
またはuseEffect
returnステートメントでそれを実行しないと、マウントされていないコンポーネントでsetState
が呼び出される問題が発生する可能性があります。
例:
componentDidMount() {
this.unlisten = this.props.history.listen((location, action) => {
if (this.state.hasError) {
this.setState({ hasError: false });
}
});
}
componentWillUnmount() {
this.unlisten();
}
エラーが検出されたら、ErrorBoundaryのエラーステータスをリセットする必要があります。以下のようなもの:
shouldComponentUpdate(nextProps, nextState) {
if (this.state.hasError && nextState.hasError === false) {
return false;
}
return true;
}
render() {
if (this.state.hasError) {
this.setState({ hasError: false });
// return fallback component to show on error
}
return this.props.children;
}
}
tl; drエラー境界のあるエラーが予想されるコンポーネントをラップしますがツリー全体ではありません
最初にwithRouter
を使用して@jdaviesの回答を試しましたが、その後、私のユースケースに適した解決策を見つけました: React-TeamのDanは、エラー境界のあるHOCを使用せず、戦略的な場所で使用するようアドバイスしました 。
そのTwitterスレッドでは、賛否両論が議論されており、Danはどちらに進むべきかを開いたままにしましたが、彼の考えは説得力があります。
だから私がしたことは、ツリー全体ではなく、エラーが予想される戦略的な場所をラップすることでした。以前よりも表現力豊かで具体的なエラーページをスローできるため、これをユースケースに使用します(問題が発生しましたvs認証エラーが発生しました)。