2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

【React】そのReact.memoはちゃんと機能していますか?

Last updated at Posted at 2021-11-13

#はじめに
React.memo、useCallback、useMemoを利用したコンポーネント、関数、値のメモ化は、実装コストが少ない分「とりあえず記述しとけ!」みたいなノリで書きがちな初心者(自分)が多そうな気がします。

しかし、意味のないメモ化はただの負債でしかないので、ちゃんと理解した上で記述できるよう、おさえておきたい内容を初心者向けに記事にしました。

React.memo、useCallback、useMemoってなんや!?って方は、以前書いた記事を参考にしていただければと思います。

#JavaScriptのデータ型
まずおさえておきたいのは、JavaScriptのデータ型についてです。

JavaScriptのデータ型は基本型と参照型に分類されます。

  • 基本型:number, string, boolean, synbol, null/undefined
  • 参照型:array, object, function

これらは値を変数に格納する方法が異なります。
基本型の変数には値そのものが直接格納されますが、参照型の変数には値を格納しているメモリ上のアドレス(ポインタ、参照値)が格納されます

#Reactのレンダリング
"Add a Boxer"でReact.memoでメモ化したBoxerコンポーネントを追加するケースを考えます。
スクリーンショット 2021-11-13 12.02.08.png

App.jsx
const Boxer = React.memo(({ name, punch }) => {
  console.log(`rendering ${name}`);
  return <p onClick={() => punch(name)}>{name}</p>;
});

const App = () => {
  const [boxers, setBoxers] = useState(['Ippo', 'Sendo', 'Mashiba']);

  const punch = (name) => console.log(`${name} has punched`);

  return (
    <>
      {boxers.map((name, i) => (
        <Boxer key={i} name={name} punch={punch} />
      ))}

      <button onClick={() => setBoxers([...boxers, prompt('Name a boxer')])}>
        Add a Boxer
      </button>
    </>
  );
};

コードを一見すると、Boxerを追加したとき、既存コンポーネントのPropsであるnamepunchに変化はなさそうです。
メモ化が成功して、既存コンポーネントの再レンダリングは起こらないようにみえます。

しかし、実はこれ、再レンダリングが起こります
スクリーンショット 2021-11-13 11.58.56.png

この理由を考えるときに、前項の「JavaScriptのデータ型」を理解している必要があります。

BoxerのPropsであるpunchには関数が設定されています。

関数のデータ型は参照型であり、描画のたびに異なるインスタンスが生成されます(格納されるメモリのアドレスが変わります)。
結果、punchの値が変化したとみなされて、Boxerコンポーネントが再描画されることになるというわけです。

それでは、関数punchの値が変化したとみなされないようにはどうすればいいのか...
ここで使用するのがuseCallbackです。

punch()useCallbackでメモ化してみます。

const punch = useCallback((name) => console.log(`${name} has punched`), []);

再度Boxerを追加してみると、今度は既存コンポーネントの再レンダリングが行われなくなりました。
スクリーンショット 2021-11-13 12.08.11.png

#まとめ
React.memoを使うときは、ラップするコンポーネントのPropsのデータ型に気をつけて、関数のような参照型が含まれる場合は必ずuseCallbackで合わせてメモ化しましょう!

#参考資料

JavaScript本格入門 山田祥寛 著

オブジェクト指向でなぜつくるのか 平澤章 著

Reactハンズオンラーニング Alex Banks, Eve Porcello 著

2
2
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
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?