問題
動的ルーティング(dynamic routing)で生成されるページ内で、パス情報に依存したデータを外部取得している。
他のページから移動したときは正常にデータを取得できるのに、動的パスのページ間で移動すると前のデータが残ってしまう!
TL;DR
_app.tsxファイルをこの状態から
function MyApp({ Component, pageProps}: AppProps) {
return (
...省略...
<Component {...pageProps} />
);
}
↓下記のように、router.asPathを元にkey属性を指定すればOK
function MyApp({ Component, pageProps, router }: AppProps) {
return (
...省略...
<Component {...pageProps} key={router.asPath} />
);
}
解説
こちらのissueで話し合われている内容です。
根本的な原因は、動的ルーティングで生成されるページコンポーネントにkey属性がデフォルトで付いてないため、ルーティングされてもその内容が上手く更新されない事のようです。
なので_app.tsxにあるグローバルなコンポーネントにkeyを付ければ解決するという、分かってみれば非常に分かりやすい解決策でした。
解決してくれたコメント 先月末のコメント、ツイてるな~
in my case
ちなみにissueはgetStaticPropsなどの外部データロード用の関数についてでしたが、自分の場合は別ファイルにあるサンプル日記データを、動的パスに含まれる日付をもとに検索して、その日の日記を取得し、useReducer()のinitialValueにセットして過去の日記を見るページを作っているときにこの問題にぶつかりました。
ある日の日記から別の日の日記に移動しようとすると、日記の内容が前のままになってしまう状態でした。
上記の方法でreducerのstateを直接反映する部分はスマートに解決できたのですが、
一点、stateのプロパティの内容を判定して日記の記入状態(empty or filled)を表示する部分は、useEffectのdependancyListに「stateに一意の値」(この場合は日記の日付)を指定する必要がありました。
const [status, setStatus] = useState<Status>("empty");
useEffect(() => {
initStatus({
inputText1: field1.inputText,
inputText2: field2.inputText,
setStatus,
});
}, [state.log.date]); //以前は[]にしていた
... //2種類の入力欄がある日記が全部空かどうか判定してstatusを更新する関数
const initStatus = ({ inputText1, inputText2, setStatus }) => {
const allEmpty = [inputText1, inputText2].every((value) => !value);
if (!allEmpty) {
setStatus("filled");
} else {
setStatus("empty");
}
};