8
4

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 1 year has passed since last update.

はじめに

フックAPIリファレンスuseCallbackの存在は知っていましたが、実際に使ったことがなかったので、使い所を調べて使ってみた話をします。

useCallbackとは

メモ化してくれる関数らしいです。

なんだかパフォーマンスを上げてくれそうな気がしますね。

Todoアプリを作りながら、試してみましょう。

Todoアプリのサンプルを作成

とりあえず、簡単なTodoアプリを作成しました。

ファイル構成はこんな感じです。

  • src/Todos/index.tsx
    • Todo追加フォームと、TodoListコンポーネントをレンダリングしている
    • TodoListコンポーネントには、todosデータを渡している。
  • src/TodoList/index.tsx
    • 受け取ったtodosデータをループで表示
    • 1件1件のtodoデータは、Todoコンポーネントに渡してレンダリングしている
  • src/Todo/index.tsx
    • 受け取ったtodoデータを表示
    • 削除ボタンを表示

画面の見た目はこんな感じです。

スクリーンショット 2022-03-21 3.27.07.png

パフォーマンスの問題点を探す

無駄にレンダリングされている場所を探します。

React Developer Tools拡張機能のHighlight updates when components render.で見ても良いですが、TodoListの中でconsole.logが何回出ているかで確認してみました。

すると、Todo追加用の入力フォームに、文字を入力するたびにTodoListコンポーネントがレンダリングされていることが分かりました。

input todo.gif

<TodoList todos={todos} />

こんな感じで、TodoListコンポーネントをレンダリングしていますが、todosしか渡していません。
入力値が更新されても、todosの値は変わらないので、無駄にレンダリングされていることが分かります。

React.memoを使う

一旦本題とは別の話ですが、React.memoは、渡されたpropsの変更のみをチェックし、変更があれば、再レンダリングされます。

src/TodoList/index.tsx
-import React from "react";
+import React, { memo } from "react";
src/TodoList/index.tsx
-export default TodoList;
+export default memo(TodoList);

無駄なレンダリングは解消されました。

input todo2.gif

削除ボタンが機能していないので、使えるようにする

React.memoの話をしておく都合上削除ボタンに削除用のメソッドを渡していませんでした。

TodoListコンポーネントのレンダリングでは、todosデータ以外に、削除用関数を渡すような書き方に変えます。

<TodoList todos={todos} delTodo={delTodo} />

TodoListが無駄にレンダリングされるようになってしまった。。。

delTodo関数を渡すようにしただけで、またTodoListコンポーネントが無駄にレンダリングされるようになってしまいました。

add todo.gif

どうやら、Todosコンポーネントが再レンダリングされるたび(入力フォームに変更があるたび)に、delTodoの関数が作り直され、別物扱いとなり、TodoListコンポーネント側では、新しく作り直されたdelTodoメソッドを受け取るので、変更されたと判断され、再度、レンダリングしているようです。

useCallbackを使う

やっと本題です。

delTodoメソッドをメモ化して、新しく作られないようにします。

src/Todos/index.tsx
-<TodoList todos={todos} delTodo={delTodo} />
+<TodoList todos={todos} delTodo={useCallback(delTodo, [])} />

TodoListコンポーネントに渡しているdelTodoメソッドがメモ化され、同じものが使われるようになり、無駄なレンダリングが発生しないようになりました。

useCallback.gif

delTodoメソッドを常に同じものを使うようにメモ化しましたが、状況によっては、作り直して欲しい場合もあるかと思います。
その際は、useCallbackの第2引数の配列を使います。
例えば、hogeという変数が変わった時に、delTodoメソッドも作り直して欲しい場合、useCallback(delTodo, [hoge])となります。

おわりに

ほとんど参考にしたサイトのままとなってしまいましたが、自分の体験した使い所をご紹介しました。

参考文献

8
4
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
8
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?