isReadyとは
next.js
のRouterオブジェクトのisReady属性は、routerが完全に準備できているかどうかを表すフラグである。
isReady: boolean - Whether the router fields are updated client-side and ready for use.
Should only be used inside of useEffect methods and not for conditionally rendering on the server.
-
ルータの各項目がクライアント側で更新されてから初めて使えるようになる
-
useEffect(やcomponentDidMount)でしか使わない。サーバ側レンダリングでそれの利用を避けるべき。
-
参照の仕方
import { useRouter } from 'next/router';
export HogePage = () => {
const router = useRouter();
console.log('router:', router);
console.log('router.isReady:', router.isReady);
console.log('router.query?.a:', router.query?.a);
return (
<div>test</div>
);
};
isReadyの値
ケースバイケースで状況によってisReadyの値が変わる。
SSRページの場合
isReadyの値は常にtrueである。
CSR/SSGページの場合
初期ロード | クエリパラメータ | isReady |
---|---|---|
YES | あり | false |
YES | なし | true |
NO | あり | true |
NO | なし | true |
つまり、物理遷移やブラウザリロードで、かつクエリパラメータがある場合だけ、一瞬isReadyがfalseになることがある。
その時、クエリパラメータの値がもらえない。
利用時の注意点
初期ロード時にisReadyがfalseであれば、router.query?.aのようにクエリパラメータの値がundefinedになってしまうので、画面レンダリングでそれを直接に使わない。
遅延処理を入れてisReadyがtrueになったら、それを再描画するようにしないといけない。
- RouterReadyWaiterのようなHOCを作ったほうが良さそう
- useEffectまたはcomponentDidUpdateでisReadyを監視して
- falseなら、childrenを描画しない
- trueの場合、childrenを描画する
- childrenとしてReactコンポーネントではRouterが準備できている前提になるので、実装がラク。
- useEffectまたはcomponentDidUpdateでisReadyを監視して
なぜこうなるのか
一瞬next/routerのバグではないかと思ったが、よく考えたらそうではない。
- SSRでない限り、事前にサーバ側で事前に用意されたプリレンダリングHTMLコンテンツをそのままクライアントに返す
- つまり、クエリパラメータはプリレンダリングに影響しない
- プリレンダリング結果がテンプレートと見なすなら、それを基づく更なる描画処理はクライアントでやる
- hydration直後はrouterのクエリパラメータ無視の状態なので、isReadyがfalseになるしかない
- SSRであれば、サーバ側でレンダリングするため、子いう問題はない