LocalStorage は stateful ではないので、やみくもに実装していると更新タイミング等の管理が難しい

LocalStorage を state のように扱えるカスタムフックを作成することで、ある程度使いやすくなる

カスタムフックのコード

useLocalStorage.tsというファイルをpagesディレクトリの外に作成する

import { useEffect, useState } from "react";

export default function useLocalStorage(key: string) {
  const [value, setValue] = useState<string>("initial value");

  useEffect(() => {
    const res = window.localStorage.getItem(key);
    if (!res) {
      setValue("local storage is empty");
    }
    setValue(res);
  }, []);

  const setValueAndStorage = (newValue: string) => {
    window.localStorage.setItem(key, newValue);
    setValue(newValue);
  };

  return { value, setValueAndStorage };
}

Next.js の SSR 時にはwindowにアクセスできないため、クライアントで実行されるuseEffect内で LocalStorage にアクセスしている。

setValueAndStorage関数内では、LocalStorage を更新すると同時に state の更新をしている。

カスタムフックの使用例

先に作成したuseLocalStorageカスタムフックを使用する例

import useLocalStorage from "@/useLocalStorage";

export default function Home() {
  const { value, setValueAndStorage } = useLocalStorage("storage-key");

  return (
    <>
      <p>value: {value}</p>
      <button
        onClick={() => {
          setValueAndStorage(Math.random().toString());
        }}
      >
        setStorage
      </button>
    </>
  );
}

ボタンを押すとランダムな数値を作成して、LocalStorage の保存と再レンダリングを一緒に行う。