LoginSignup
2
1

More than 3 years have passed since last update.

[Next.js]動的ルーティングページ間で外部データが更新されない問題

Last updated at Posted at 2021-03-28

問題

動的ルーティング(dynamic routing)で生成されるページ内で、パス情報に依存したデータを外部取得している。
他のページから移動したときは正常にデータを取得できるのに、動的パスのページ間で移動すると前のデータが残ってしまう!

TL;DR

_app.tsxファイルをこの状態から

_app.tsx
function MyApp({ Component, pageProps}: AppProps) {
    return (
            ...省略...
            <Component {...pageProps} />
    );
}

↓下記のように、router.asPathを元にkey属性を指定すればOK

_app.tsx
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に一意の値」(この場合は日記の日付)を指定する必要がありました。

.tsx
    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");
    }
};

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1