🐥

useEffectよりuseMemoを活用しよう?

2021/12/05に公開

ReactでuseEffectを使った変数依存でなく,useMemoを使ったほうがスッキリしていいのでは?という仮説の話.これによる差異やデメリットが他にあればぜひご教授いただきたい所存です.

アプリを作るときに,一つの変数に依存したもうひとつの変数を作りたい場合が出てくるかと思います.

例えば,データベースに以下のようなオブジェクトがあるとします.

const colorDataBase = [
  {
    id: "0",
    name: "default",
    color: "#fff"
  },
  {
    id: "1",
    name: "red",
    color: "#f00"
  },
  {
    id: "2",
    name: "blue",
    color: "#00f"
  },
  {
    id: "3",
    name: "yellow",
    color: "#ff0"
  }
];

そんな中で,色を選択したときにフロントで保持する色のデータを書き換える必要が出てくるとしましょう.(意味がわからない場合は以下のコードを見ればわかるかと)

今回はデータベースからFetchする処理は書かずに,普通に上記のJavaScriptのオブジェクトを操作するものとします.

そのときuseEffectによる実装は多分こんな感じです.

export default function App() {
  /* 選択状態のIDを保持するState */
  const [selectedId, setSelectedId] = useState("0");
  /* 選択状態の色に関するデータを保持するState */
  const [currentData, setCurrentData] = useState({
    id: "0",
    name: "default",
    code: "#fff"
  });

  /* 選択状態が変化する度に実行する処理 */
  useEffect(() => {
    const data = colorDataBase.find((item) => item.id === selectedId);
    setCurrentData(data);
  }, [selectedId]);

  return (
    <div>
      <select
        value={selectedId}
        onChange={(e) => setSelectedId(e.target.value)}
      >
        <option value="1">red</option>
        <option value="2">blue</option>
        <option value="3">yellow</option>
      </select>
      <div># current data by useEffect & useState</div>
      <pre>{JSON.stringify(currentData, null, 2)}</pre>
    </div>
  );
}

別にこれでもいいのですが,わざわざ選択状態の色に関するデータを保持するStateuseStateを使う必要はないのでは?と思い,useMemoで書いてみました.

export default function App() {
  const [selectedId, setSelectedId] = useState("0");

  /* selectIdに依存するcurrentDataという変数を作成 */
  const currentData = useMemo(() => {
    const data = colorDataBase.find((item) => item.id === selectedId);
    return data;
  }, [selectedId]);

  return (
    <div>
      <select
        value={selectedId}
        onChange={(e) => setSelectedId(e.target.value)}
      >
        <option value="1">red</option>
        <option value="2">blue</option>
        <option value="3">yellow</option>
      </select>
      <div># current data by useMemo only</div>
      <pre>{JSON.stringify(currentData, null, 2)}</pre>
    </div>
  );
}

こっちの方がスッキリしているし,わかりやすいと私は思っています.

実際に動かしてみたのはこちら

レンダリングを軽く検証しましたが,パフォーマンスは変わらなそう?かなと思ってます.

追記
useMemoでは非同期処理は書けないみたいなので,データベースを想定したのであれば,やはり,useEffectを使うしかないということになりそうですね.

Discussion