React PR

【React入門】useCallbackの使い方5ステップ!パフォーマンス最適化のコツ

【React】useCallbackの使い方5ステップ!パフォーマンス最適化のコツ
記事内に商品プロモーションを含む場合があります

こんにちは!
Reactを使っていて、アプリの動きが遅くなってしまった経験はありませんか?
あるいは、コンポーネントが必要以上に再描画されて困っていませんか?

そんな悩みを解決してくれるのが、今回紹介するuseCallbackフックです。

useCallbackは、一見難しそうに見えるかもしれません。
でも心配いりません。
基本を押さえれば、とても役立つ道具になりますよ。

この機能を使うと、アプリの動きがスムーズになったり、余計な処理を減らしたりできるんです。
特に、大きなアプリを作るときに重宝します。
関数を記憶しておいてくれる特別な機能だと思えば、イメージしやすいかもしれませんね。

Reactでは、コンポーネントの状態が変わるたびに再描画が行われます。
これは通常は問題ありませんが、大規模なアプリケーションになると、不要な再描画が発生して動作が遅くなることがあります。
useCallbackを使えば、そういった無駄な再描画を減らすことができるんです。
特に、子コンポーネントに関数を渡す時に重宝しますよ。

この記事を読めば、以下のようなことがわかるようになります。

この記事でわかること
  • useCallbackフックの基本的な概念と使い方
  • useCallbackを使うメリットと注意点
  • 実際のコード例を通じたuseCallbackの活用方法
  • Reactアプリのパフォーマンス最適化のコツ

React環境がない方はこちらも参考にしてください。

【たった1分】React×Vite×TypeScriptで高速ビルド環境を構築する方法
【たった1分】React×Vite×TypeScriptで高速ビルド環境を構築する方法こんにちは! 今日は、React、Vite(ヴィート)、TypeScriptを使用して、たった1分で高速にビルド環境を構築する方法につ...

useCallbackとは

useCallbackは、Reactが提供する便利な道具の一つ。
簡単に言うと、関数を記憶しておいてくれる特別な機能なんです。
この機能を使うと、アプリの動きがスムーズになったり、余計な処理を減らしたりできるんですよ。

なぜuseCallbackを使う必要があるのか

Reactでは、コンポーネントの状態が変わるたびに再描画が行われます。
これは通常は問題ありませんが、大規模なアプリケーションになると、不要な再描画が発生して動作が遅くなることがあります。

useCallbackを使うと、そういった無駄な再描画を減らすことができるんです。
特に、子コンポーネントに関数を渡す時に重宝します。
パフォーマンスを上げたい!という方には、とても強力な味方になってくれますよ。

useCallbackの基本

関数のメモ化とは

メモ化って聞くと難しそうに感じますよね。
でも、実はとてもシンプルな考え方なんです。

メモ化とは、計算結果や関数を記憶しておくことを指します。
一度計算した結果を覚えておいて、同じ計算を求められたら、また一から計算するのではなく、記憶しておいた結果をそのまま返すんです。
これにより、無駄な計算を省くことができるんですよ。

useCallbackとuseMemoの違い

ReactにはuseCallbackの他にuseMemoというフックもあります。
どちらも似たような役割を持っていますが、使い方が少し違います。

useCallbackは関数自体を記憶するのに対し、useMemoは関数の結果を記憶します。
つまり、useCallbackは「関数を作る方法を覚えておく」のに対し、useMemoは「関数の結果を覚えておく」という違いがあるんです。

初心者の方は、まずはuseCallbackから使いこなせるようになりましょう。
慣れてきたらuseMemoも試してみてくださいね。

useCallbackの使い方5ステップ

useCallbackの使い方を、5つの簡単なステップで説明していきます。
初めて使う方も、これを順番に進めていけば大丈夫ですよ。

1) import文を追加する

まずは、useCallbackを使うために必要な準備をしましょう。
Reactファイルの先頭に、以下のようなimport文を追加します。


import React, { useCallback } from 'react';

これで、useCallbackを使う準備が整いました。

2) コールバック関数を定義する

次に、useCallbackで包む関数を定義します。
これは普通の関数と同じように書けます。
例えば、ボタンをクリックしたときの処理を書く関数を考えてみましょう。


const handleClick = useCallback(() => {
  console.log('ボタンがクリックされました!');
}, []);

3) 依存配列を設定する

useCallbackの第二引数には、依存配列というものを設定します。
これは、関数の中で使われている値のリストです。
この値が変わったときだけ、関数が新しく作り直されます。
空の配列[]を指定すると、コンポーネントが初めて表示されるときにだけ関数が作られます。

4) メモ化された関数を使用する

定義した関数は、普通の関数と同じように使えます。
例えば、ボタンのonClickプロパティに設定したりできます。


return (
  <button onClick={handleClick}>クリックしてね</button>
);

5) パフォーマンスの変化を確認する

最後に、useCallbackを使う前と後で、アプリの動きがどう変わったかを確認しましょう。
大きな違いがなくても心配いりません。
useCallbackの効果は、アプリが大きくなればなるほど顕著に現れます。

これでuseCallbackの基本的な使い方は完了です!
少し難しく感じるかもしれませんが、何度か使ってみるうちに慣れてきますよ。

useCallbackの具体的な使用例

useCallbackの効果を実感するには、実際のコード例を見比べるのが一番わかりやすいですね。
ここでは、useCallbackを使用するケースと使用しないケースを比較して、再描画時の違いを見ていきましょう。

useCallbackを使用しない場合

まずは、useCallbackを使用しないコンポーネントの例を見てみましょう。


import React, { useState } from "react";

const ParentComponent: React.FC = () => {
  const [count, setCount] = useState(0);

  const handleClick = () => {
    console.log("ボタンがクリックされました");
    setCount((c) => c + 1);
  };

  return (
    <div>
      <p>カウント: {count}</p>
      <ChildComponent onClick={handleClick} />
    </div>
  );
};

const ChildComponent: React.FC<{ onClick: () => void }> = React.memo(
  ({ onClick }) => {
    console.log("子コンポーネントがレンダリングされました");
    return <button onClick={onClick}>カウントを増やす</button>;
  }
);

export default ParentComponent;

この例では、ParentComponentcountが変更されるたびに、handleClick関数が新しく作られます。
そのため、ChildComponentも再描画されてしまいます。
これは、アプリの動きが遅くなる原因になりかねません。

useCallbackを使用する場合

次に、同じ機能をuseCallbackを使って作ってみましょう。


import React, { useState, useCallback } from "react";

const ParentComponent: React.FC = () => {
  const [count, setCount] = useState(0);

  const handleClick = useCallback(() => {
    console.log("ボタンがクリックされました");
    setCount((c) => c + 1);
  }, []);

  return (
    <div>
      <p>カウント: {count}</p>
      <ChildComponent onClick={handleClick} />
    </div>
  );
};

const ChildComponent: React.FC<{ onClick: () => void }> = React.memo(
  ({ onClick }) => {
    console.log("子コンポーネントがレンダリングされました");
    return <button onClick={onClick}>カウントを増やす</button>;
  }
);

export default ParentComponent;

この例では、handleClick関数がuseCallbackで包まれています。
空の配列を渡しているので、この関数はコンポーネントが初めて表示されるときにだけ作られます。
これにより、不要な再描画を防ぐことができるんです。

再描画時の違い

これらの2つの例の違いは、ParentComponentcountが変更されたときに現れます。

useCallbackを使用しない場合

  • countが変更されるたびにhandleClick関数が新しく作成されます。
  • 新しいhandleClick関数がChildComponentに渡されるため、ChildComponentも再レンダリングされます。
  • コンソールには「子コンポーネントがレンダリングされました」というメッセージが表示されます。

useCallbackを使用する場合

  • countが変更されても、handleClick関数は新しく作成されません。
  • ChildComponentに渡されるhandleClick関数は変更されないため、ChildComponentは再レンダリングされません。
  • コンソールには「子コンポーネントがレンダリングされました」というメッセージは表示されません。

この違いは、特に子コンポーネントの処理が重い場合や、たくさんの子コンポーネントがある場合に重要になります。
不要な再描画を防ぐことで、アプリ全体の動きが速くなるんです。

実際にこのコードを動かしてみると、違いがよく分かりますよ。
カウントを増やすボタンをクリックしたときのコンソールの出力を見てみてください。
useCallbackを使った場合、子コンポーネントの再描画が起きないことが確認できるはずです。

このように、useCallbackを上手に使うことで、不要な再描画を防ぎ、アプリの動きを速くすることができます。
ただし、すべての関数にuseCallbackを使う必要はありません。
再描画にかかる時間とuseCallbackを使うことのバランスを考えて、適切な場所で使うことが大切です。
少しずつ試してみて、自分のアプリに合った使い方を見つけていきましょう。

useCallbackを使う際の注意点

useCallbackは便利な機能ですが、使い方を間違えると逆効果になることもあります。
ここでは、useCallbackを使う際の注意点をいくつか紹介します。

過剰な最適化を避ける

useCallbackは確かに便利ですが、すべての関数に使えばいいというわけではありません。
小規模なアプリケーションや、頻繁に再レンダリングが起こらないコンポーネントでは、useCallbackを使う必要がない場合もあります。
むしろ、過剰に使用すると、コードが複雑になってしまう可能性があります。

重要なのは、本当に必要な場所で使うことです。
例えば、子コンポーネントに渡す関数や、依存配列に使用される関数など、再レンダリングの影響が大きい部分に限定して使うのがいいでしょう。
最適化の必要性を感じたときに、少しずつ導入していくのがおすすめです。

依存配列の正しい設定

useCallbackの依存配列は、とても重要な役割を果たします。
正しく設定しないと、予期せぬバグの原因になることがあります。
依存配列には、関数内で使用している全ての変数や関数を含める必要があります。

例えば、こんなコードがあったとします。


const Example: React.FC = () => {
  const [count, setCount] = useState(0);

  const increment = useCallback(() => {
    setCount(count + 1);
  }, []); // これは正しくありません

  return (
    <button onClick={increment}>増やす(現在: {count})</button>
  );
};

このコードでは、increment関数がcountを使用しているにもかかわらず、依存配列が空になっています。
これでは、ボタンをクリックしてもcountが更新されません。

正しくは以下のようになります。


const increment = useCallback(() => {
  setCount(count + 1);
}, [count]); // countを依存配列に含める

または、さらに良い方法として。


const increment = useCallback(() => {
  setCount(prevCount => prevCount + 1);
}, []); // 関数型更新を使用すれば、依存配列は空でOK

このように、依存配列の設定には注意が必要です。
関数内で使用している値が変更されたときに、確実に新しい関数が作られるようにしましょう。

これらの注意点を守ることで、useCallbackを効果的に使用できます。
最適化は徐々に行っていき、その都度パフォーマンスの変化を確認するのがベストな方法です。

useCallbackのメリット

useCallbackを使うことで、いくつかの大きなメリットがあります。
ここでは、主な2つのメリットについて詳しく見ていきましょう。

不要な再レンダリングの防止

Reactでは、親コンポーネントが再レンダリングされると、その子コンポーネントも再レンダリングされます。
これは、アプリケーションの規模が大きくなると、パフォーマンスの低下につながる可能性があります。

useCallbackを使うと、関数が新しく作られるのを防ぐことができます。
つまり、親コンポーネントが再レンダリングされても、子コンポーネントに渡す関数は変わらないので、子コンポーネントの不要な再レンダリングを防げるんです。

アプリケーションのパフォーマンス向上

useCallbackを適切に使用することで、アプリケーション全体のパフォーマンスを向上させることができます。
特に、以下のような場合に効果を発揮します。

  1. 大規模なアプリケーション:コンポーネントの数が多い場合、useCallbackによる最適化の効果が顕著に現れます。
  2. 頻繁に更新される状態がある場合:例えば、入力フォームやリアルタイムデータ更新などの機能がある場合です。
  3. 重い処理を行う関数:計算量の多い関数や、APIリクエストを行う関数などをuseCallbackでラップすることで、不要な再計算や再リクエストを防げます。

ただし、すべての関数をuseCallbackでラップする必要はありません
小規模なアプリケーションや、単純な関数の場合は、useCallbackを使用しない方がコードがシンプルになることもあります。
適材適所で使用することが大切です。

これらのメリットを理解し、適切にuseCallbackを使用することで、よりスムーズで効率的なReactアプリケーションを作ることができます。
パフォーマンスの向上は、ユーザー体験の向上にもつながります。
ぜひ、自分のプロジェクトで試してみてくださいね。

キャリア形成/給与還元
ひとつひとつ真摯に向き合う企業
ONE_WEDGE社員募集

株式会社 ONE WEDGEでは、新たな仲間を募集しています!

私たちと一緒に、革新的で充実したキャリアを築きませんか?
当社は、従業員が仕事と私生活のバランスを大切にできるよう、充実した福利厚生を整えています。

  • 完全週休2日制(土日休み)で、祝日や夏季休暇、年末年始休暇もしっかり保証!
  • 様々な休暇制度(有給、慶弔、産前・産後、育児、バースデー休暇)を完備!
  • 従業員の成長と健康を支援するための表彰制度、資格取得支援、健康促進手当など!
  • 生活を支えるテレワーク手当、記事寄稿手当、結婚祝金・出産祝金など、様々な手当を提供!
  • 自己啓発としての書籍購入制度や、メンバー間のコミュニケーションを深める交流費補助!
  • 成果に応じた決算賞与や、リファラル採用手当、AI手当など、頑張りをしっかり評価!
  • ワークライフバランスを重視し、副業もOK!

株式会社 ONE WEDGEでは、一人ひとりの従業員が自己実現できる環境を大切にしています。
共に成長し、刺激を与え合える仲間をお待ちしております。
あなたの能力と熱意を、ぜひ当社で発揮してください。
ご応募お待ちしております!

ホームページ、採用情報は下記ボタンからご確認ください!

応募、ご質問など、LINEでお気軽にご相談ください♪

まとめ

ここまでuseCallbackについて詳しく見てきました。
最後に、重要なポイントを振り返り、実践的なアドバイスをお伝えしましょう。

useCallbackの重要ポイント復習

  1. 関数のメモ化useCallbackは関数をメモ化し、不要な再作成を防ぎます。
  2. 依存配列の重要性:正しく依存配列を設定することで、必要なときにだけ関数が再作成されます。
  3. パフォーマンス最適化:特に子コンポーネントに渡す関数で効果を発揮します。
  4. 過剰な使用に注意:すべての関数に使う必要はありません。適材適所で使いましょう。
  5. 大規模アプリケーションでの威力:アプリケーションの規模が大きくなるほど、useCallbackの効果が顕著になります。

実践的な使用のアドバイス

  1. 段階的な導入:一度にすべての関数をuseCallbackで包むのではなく、パフォーマンスの問題が見られる部分から少しずつ導入していきましょう。
  2. パフォーマンス計測:React Developer Toolsなどのツールを使って、useCallback導入前後でのパフォーマンスの変化を確認しましょう。
  3. コードの可読性とのバランスuseCallbackの使用でコードが複雑になりすぎないよう注意しましょう。シンプルさと最適化のバランスが大切です。
  4. チームでの共有useCallbackの使用方針をチームで共有し、一貫した使用を心がけましょう。
  5. 最新のReactの動向をキャッチアップ:Reactは常に進化しています。将来的にはuseCallbackの使用が不要になる可能性もあるので、最新の情報をチェックしましょう。

useCallbackは強力なツールですが、万能薬ではありません。
アプリケーションの特性や規模に応じて、適切に使用することが大切です。
この記事で学んだことを基に、自分のプロジェクトで試してみてください。
実際に使ってみることで、より深い理解が得られるはずです。

React開発の世界は奥が深く、学ぶべきことがたくさんあります。
useCallbackはその一歩に過ぎません。
これからも楽しみながら、スキルアップを続けていきましょう!

COMMENT

メールアドレスが公開されることはありません。 が付いている欄は必須項目です