🤢
ReactRouter6のuseNavigateはlocationが変わると別物を返す
ReactRouterを使ってるプロジェクトで、そろそろv6に上げるかと腰を上げたところ、予期せぬ罠を踏みました。
v5までは
const history = useHistory();
useEffect(() => {
history.push(`/items/${itemId}`);
}, [history, itemId]);
のように書いていたコードは、v6ではuseNavigateを使って
const navigate = useNavigate();
useEffect(() => {
navigate(`/items/${itemId}`);
}, [navigate, itemId]);
のように書くのですが、v6ではこのuseEffect
はブラウザバックなどで戻ってきた場合にも発火してしまいます。
- https://github.com/remix-run/react-router/issues/7634
- https://github.com/remix-run/react-router/issues/8349
どうやらlocationが変わった時にuseNagivate
が別の参照を返すようになったらしく、これまでと同じ動作を期待していると予期せぬ不具合を招いてしまいます。
issueではいくつかのworkaroundも提唱されていますが、簡単にシュッと解決できる雰囲気ではなくて、なかなか厳しい感じになっています。
手元のコードでは目先の移行のために// eslint-disable-next-line react-hooks/exhaustive-deps
宣言して、依存からnavigate
を外して通してみたけど、このまま放置したくなくて悩ましい…
これ結構な困りごとだと思うんだけど、中の人と思しき人物が「これで再レンダリングされたところで実際言うほどパフォーマンス劣化する?」みたいにコメントしてたりして、公式の温度感が今ひとつ訝しい感もあります。
個人的にはフルスタックなライブラリをなるべく避けたくて独立性の高いReactRouterを使ってきたけど、Remixの一部みたいな位置付けになってくるとこれまでと同じようには考えられない場面も増えてくるかもしれないですね。
Discussion