Roa run dev

ReactフックuseRef【基本】

●目次

    ReactのuseRefは、DOMの直接操作や、レンダリングに影響しない一時的なデータの保存に非常に便利なフックです。

    本記事では、useRefの基礎から使い所、useStateとの違い、実践的な活用例までを網羅的にわかりやすく解説します。

    useRefとは?(定義と特徴)

    useRefは、「参照(Reference)」を作成するためのフックです。

    通常、状態管理にはuseStateを使いますが、useRefは再レンダリングを発生させずにデータを保持したい場合に使います。

    JS
    const ref = useRef(初期値);
    • 再レンダリングを引き起こさない
      • useRefで保持した値が変化しても、コンポーネントは再レンダリングされません。
    • .currentプロパティ
      • useRefはオブジェクトを返し、その中の.currentプロパティに値を保持します。

    useRefuseStateの違い

    useRefuseState
    再レンダリングしない再レンダリングする
    ref.current(値)を
    直接更新
    セッター関数を使用して
    値を更新
    用途:
    ・値の保持
    ・DOM操作
    用途:
    ・状態管理
    ・画面の再描画

    useRefの基本的な使い方(値の保持)

    • useRef(0)初期値を0に設定した参照を作成します。
    • countRef.current現在の値を取得または更新します。
    • コンソールにクリック回数が表示されますが、画面上の表示は変わりません。
    App.jsx
    import React, { useRef } from 'react';
    
    function App() {
    
      const countRef = useRef(0);
    
      const handleClick = () => {
        countRef.current += 1;
        console.log(`クリック回数: ${countRef.current}`);
      };
    
      return (
        <div>
          <button onClick={handleClick}>クリックしてね!</button>
        </div>
      );
    
    }
    
    export default App;

    useRefでDOM要素へのアクセス

    useRefは、直接DOM要素にアクセスしたい場合にも使われます。

    • input ref={inputRef} /input要素に参照を設定します。
    • inputRef.current.focus()input要素にフォーカスを当てます。
    App.jsx
    import React, { useRef } from 'react';
    
    function App() {
      const inputRef = useRef(null);
    
      const focusInput = () => {
        inputRef.current.focus();
      };
    
      return (
        <div>
          <input ref={inputRef} type="text" />
          <button onClick={focusInput}>フォーカスを当てる</button>
        </div>
      );
    }
    
    export default App;

    実践的な例:タイマーの作成

    • 「開始」ボタンを押すと1秒ごとにカウントアップ
    • 「停止」ボタンでタイマーを止める
    Timer.jsx
    import React, { useRef, useState } from 'react';
    
    function Timer() {
      const [time, setTime] = useState(0);
      const timerRef = useRef(null);
    
     // タイマーを開始する関数
      const startTimer = () => {
        if (timerRef.current !== null) return;
        timerRef.current = setInterval(() => {
          setTime((prev) => prev + 1);
        }, 1000);
      };
    
     // タイマーを停止する関数
      const stopTimer = () => {
        clearInterval(timerRef.current);
        timerRef.current = null;
      };
    
      return (
        <div>
          <h1>時間: {time}秒</h1>
          <button onClick={startTimer}>開始</button>
          <button onClick={stopTimer}>停止</button>
        </div>
      );
    }
    
    export default Timer;

    状態と参照の定義

    • time:表示用の状態。更新されるたびに画面が再描画される
    • timerRef:タイマーIDを保存。再描画は不要なのでuseRefで管理
    JS
    const [time, setTime] = useState(0);
    const timerRef = useRef(null);

    タイマーの開始処理・タイマーの停止処理

    • 2重起動を防止するため、timerRef.current !== null なら処理しない
      • すでにタイマーが動いていたらスキップ(2重起動を防止)
    • setInterval1秒ごとに setTime() を実行(timeが+1)
    • setIntervalの返り値(ID)をtimerRef.currentに保存
    JS
    const startTimer = () => {
      if (timerRef.current !== null) return;
      timerRef.current = setInterval(() => {
        setTime((prev) => prev + 1);
      }, 1000);
    };

    • clearInterval()でタイマー停止(引数はtimer ID)
    • timerRef.currentnull に戻すことで、再び startTimer() を使える状態にする
    JS
    const stopTimer = () => {
      clearInterval(timerRef.current);
      timerRef.current = null;
    };

    JSX部分(UI)

    • 秒数をリアルタイムに表示(timeはstateなので再レンダリングされる)
    • ボタン操作で関数を発火
    JS
    <h1>時間: {time}秒</h1>
    <button onClick={startTimer}>開始</button>
    <button onClick={stopTimer}>停止</button>

    まとめ

    • useRefはレンダリングに影響しない変数・参照を管理するためのReactフック
    • DOM要素へのアクセス、値の一時保存、クリーンアップ対象の管理など幅広く活用可能
    • useStateと明確に使い分けることで、パフォーマンスの高いUI構築が実現できます