👻

[React] コンポーネント内でデータを扱いたければuseRefで事足りるという事実

2021/11/15に公開

コンポーネント内でデータを扱いたければuseRefで事足りるという事実

動作確認はこちら

https://codesandbox.io/s/react-ref-data-cx3dj?file=/src/App.tsx

ソースコード

import { useEffect, useRef, useState } from "react";
const Page = () => {
  const [_, dispatch] = useState<{}>();
  const that = useRef({ count: 1, text1: "", text2: "" }).current;
  useEffect(() => {
    const handle = setInterval(() => {
      ++that.count;
      dispatch({});
    }, 1000);
    return () => clearInterval(handle);
  }, []);

  return (
    <>
      <input
        value={that.text1}
        onChange={(e) => {
          that.text1 = e.currentTarget.value;
          dispatch({});
        }}
      />
      <input
        value={that.text2}
        onChange={(e) => {
          that.text2 = e.currentTarget.value;
          dispatch({});
        }}
      />
      <div>count:{that.count}</div>
      <div>text1:{that.text1}</div>
      <div>text2:{that.text2}</div>
    </>
  );
};

export default Page;

useStateの大量生産はいらなかった

このプログラム、扱うデータはuseRefで作成した領域にしか保存していません。useStateは、再レンダリングを発生させるためだけにdispatchを取り出しています。

useRefから作成したthatが、クラスコンポーネントのthis相当となります。

実はほとんどのプログラムでこの方法が使用できます。変数を書き換えた後に再レンダリングしたければ、dispatchを呼び出せば良いのです。

useRefにデータを保存する利点

useEffectやuseCallbackでstateの更新タイミングを気にする必要がありません。そこにあるのはリアルタイムなデータです。変数更新のためだけに、第二引数でトリガーになるstateを並べる必要もありません。

useRefにデータを保存する欠点

dispatchを呼び出す前に書き換えるべき値と元の変数の値が異なっているかどうかの確認を入れないと、内容が変わっていないのに再レンダリングされます。そういう可能性のある場所に判定を一個加える必要があるというのが欠点ですが、大した労力ではありません。

まとめ

うん、なんでもあり

GitHubで編集を提案

Discussion