🤢

ReactRouter6のuseNavigateはlocationが変わると別物を返す

2022/07/22に公開

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はブラウザバックなどで戻ってきた場合にも発火してしまいます。

どうやらlocationが変わった時にuseNagivateが別の参照を返すようになったらしく、これまでと同じ動作を期待していると予期せぬ不具合を招いてしまいます。

issueではいくつかのworkaroundも提唱されていますが、簡単にシュッと解決できる雰囲気ではなくて、なかなか厳しい感じになっています。

手元のコードでは目先の移行のために// eslint-disable-next-line react-hooks/exhaustive-deps宣言して、依存からnavigateを外して通してみたけど、このまま放置したくなくて悩ましい…

これ結構な困りごとだと思うんだけど、中の人と思しき人物が「これで再レンダリングされたところで実際言うほどパフォーマンス劣化する?」みたいにコメントしてたりして、公式の温度感が今ひとつ訝しい感もあります。

個人的にはフルスタックなライブラリをなるべく避けたくて独立性の高いReactRouterを使ってきたけど、Remixの一部みたいな位置付けになってくるとこれまでと同じようには考えられない場面も増えてくるかもしれないですね。

Discussion