0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

useEffect, useRef, useCallbackを組み合わせて実装するパターン例

Last updated at Posted at 2025-06-03

はじめに

ReactのHooksである useEffectuseRefuseCallback はそれぞれ便利ですが、組み合わせることでより実用的なユースケースが生まれます。

本記事では、「ボタンを押すと一定間隔でカウントが進み、停止もできる」簡単な例を使って、3つのHookを組み合わせて解説します。

各Hookの役割

  • useRef:DOM要素やミューテーション可能な値の保持に使います。再レンダリングを発生させません。
  • useEffect:副作用の処理に使います。マウント、アンマウント、依存値の変化に応じて発火します。
  • useCallback:関数をメモ化して、不要な再生成を防ぎます。子コンポーネントへの渡しや、useEffectの依存に便利。

スタート・ストップ機能付きカウンター

Timer.tsx
import { useState, useRef, useEffect, useCallback } from "react";

export default function Timer() {
  const [count, setCount] = useState(0);
  const [isRunning, setIsRunning] = useState(false);
  const intervalRef = useRef<NodeJS.Timeout | null>(null);

  // カウントアップ関数(useCallbackでメモ化)
  const tick = useCallback(() => {
    setCount(prev => prev + 1);
  }, []);

  // スタート関数
  const start = useCallback(() => {
    if (!intervalRef.current) {
      intervalRef.current = setInterval(tick, 1000);
      setIsRunning(true);
    }
  }, [tick]);

  // ストップ関数
  const stop = useCallback(() => {
    if (intervalRef.current) {
      clearInterval(intervalRef.current);
      intervalRef.current = null;
      setIsRunning(false);
    }
  }, []);

  // アンマウント時にクリーンアップ
  useEffect(() => {
    return () => {
      stop();
    };
  }, [stop]);

  return (
    <div className="p-4 text-center">
      <h2 className="text-xl mb-2">⏱️ Count: {count}</h2>
      <button onClick={start} disabled={isRunning} className="px-4 py-2 bg-blue-500 text-white rounded mr-2">
        Start
      </button>
      <button onClick={stop} disabled={!isRunning} className="px-4 py-2 bg-gray-500 text-white rounded">
        Stop
      </button>
    </div>
  );
}

🔍 ポイント解説

useRefの活用

  • intervalRefはsetIntervalのIDを保持し、再レンダリングを防ぎつつ、start/stop間で情報を共有しています。

useCallbackで関数をメモ化

  • tick, start, stop すべて useCallback でメモ化。useEffectの依存や、再レンダリングで不要に関数が再生成されるのを防ぎます。

useEffectでクリーンアップ処理

  • コンポーネントのアンマウント時に stop() を呼び出してメモリリークを防いでいます。

おわりに

useRef, useEffect, useCallback をうまく組み合わせることで、より堅牢でパフォーマンスの良いReactコンポーネントを作ることができます。

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

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?