【React】useRefの使い方を分かりやすく解説!

この記事ではReactフックの1つである『useRef』について、

  • useRefとは
  • useRefの構文
  • useRefの使い方
    • useRefでDOM要素を参照する方法
    • useRefで値を保存する方法

などをサンプルコードや図を用いて分かりやすく説明するように心掛けています。ご参考になれば幸いです。

useRefとは

ReactのuseRefは、Reactフックの一つで、主に「DOM要素への参照の保持」と「値の保存」の2つの目的で使われます。

  • DOM要素への参照の保持
    • useRefを用いると、refオブジェクトを作成することができます。この作成されたrefオブジェクトを、JSX内の特定のDOM要素に関連付けることで、その要素への参照を保持できます。
    • 直接的なDOM操作(フォーカスを設定する、特定のアニメーションを直接適用するなど)に役立ちます。
  • 値の保存
    • useRefで作成されたrefオブジェクトはcurrentプロパティを介してアクセスされる値を持っており、このプロパティは更新可能で、その値が更新されてもコンポーネントの再レンダリングが起きないのが特徴です。

useRefの構文

useRefの構文を以下に示します。

useRefの構文

const refContainer = useRef(initialValue);
  • refContainer
    • refオブジェクトを保持する変数です。
    • refオブジェクトはcurrentプロパティを通じて、保持している値へアクセスすることができます。
  • useRef
    • useRefは引数としてinitialValueを取ります。
  • initialValue(省略可能)
    • refオブジェクトの初期値です。省略した場合はundefinedになります。
    • refオブジェクトをDOM要素に関連付ける場合には、initialValuenullにします。

useRefの使い方

useRefについて、以下に示している使い方をこれから説明します。

  • useRefでDOM要素を参照する方法(この使い方が圧倒的に多い)
    • useRefでDOM要素にフォーカスを設定する
    • useRefでCSSのスタイルを変更する
  • useRefで値を保存する
    • useRefでタイマーを管理する

上記の使い方について順番に説明します。

useRefでDOM要素を参照する方法

useRefでDOM要素を参照しているサンプルコードを以下に示します。この使い方が圧倒的に多いです。

import React, { useRef } from 'react';

function App() {
  // useRefでrefオブジェクト(ここではinputEl)を作成し、初期値をnullとする
  const inputEl = useRef(null);

  const onButtonClick = () => {
    // コンソールにrefオブジェクト(ここではinputEl)の値を出力
    console.log(`refオブジェクトの値: ${inputEl.current.value}`);
  };
  return (
    <>
      <input type="text" ref={inputEl} defaultValue="hello" />
      <button onClick={onButtonClick}>refオブジェクトの値をログ出力</button>
    </>
  );
}

export default App;

上記のサンプルコードについてこれから説明します。

まず、上記のサンプルコードの以下の箇所ではuseRefをインポートしています。useRefはインポートしなくても使えますが、インポートしない場合には、useRef()React.useRef()にする必要があります。

import React, { useRef } from 'react';

上記のサンプルコードの以下の箇所ではuseRefrefオブジェクトを作成しています。このコードではタイトル入力用の<input>要素への参照を保持するrefオブジェクト(ここではinputEl)を作成しています。refオブジェクトをDOM要素に関連付ける場合には、useRefの引数をnullにします。

const inputEl = useRef(null);

上記のサンプルコードの以下の箇所ではuseRefで作成したrefオブジェクト(ここではinputEl)をJSXのref属性に設定しています。refオブジェクトをJSXのref属性に設定することで、refオブジェクトのcurrentプロパティ経由でDOM要素(ここでは<input>要素)にアクセスすることができるようになります。

<input type="text" ref={inputEl} defaultValue="hello" />

上記のサンプルコードの以下の箇所では、refオブジェクト(ここではinputEl)のcurrentプロパティでDOM要素(ここでは<input>要素)にアクセスしています。

console.log(`refオブジェクトの値: ${inputEl.current.value}`);

useRefrefオブジェクトとDOM要素の関係を図で表すと以下のようになります。

useRefの使い方

useRefでDOM要素にフォーカスを設定する

useRefを使うことでDOM要素にアクセスができるため、DOM要素にフォーカスをさせることができます。サンプルコードを以下に示します。

import React, { useRef } from 'react';

function App() {
  // useRefでrefオブジェクト(ここではinputEl)を作成し、初期値をnullとする
  const inputEl = useRef(null);

  const onButtonClick = () => {
    inputEl.current.focus(); // 対象の要素をフォーカスする
  };
  return (
    <>
      <input type="text" ref={inputEl} />
      <button onClick={onButtonClick}>input要素にフォーカス</button>
    </>
  );
}

export default App;

「input要素にフォーカス」ボタンをクリックすると、テキスト入力欄にフォーカスします。

onButtonClick関数では、inputEl.currentでフォーカスする対象のDOM要素(ここでは<input>要素)を参照し、その要素に対してfocus()メソッドを実行して、フォーカス処理を行っています。

JavaScriptでdocument.getElemetById("対象のID").focus()でフォーカスするのと同じ処理です。

useRefでCSSのスタイルを変更する

useRefを使うことでDOM要素にアクセスができるため、対象のDOM要素をCSSでスタイル変更することができます。サンプルコードを以下に示します。

import React, { useRef } from 'react';

function App() {
  // useRefでrefオブジェクト(ここではtextEl)を作成し、初期値をnullとする
  const textEl = useRef(null);

  const onButtonClick = () => {
    textEl.current.style.color = 'red'; // テキスト(Hello)を赤色に変える
  };
  return (
    <>
      <p ref={textEl}>Hello</p>
      <button onClick={onButtonClick}>Helloを赤色に変える</button>
    </>
  );
}

export default App;

「Helloを赤色に変える」ボタンをクリックすると、画面上に表示されている文字列Helloの色が赤色に変わります。

useRefで値を保存する

以下に示すのは、ReactのuseRefフックを使って値を保存し、その値を更新してもコンポーネントが再レンダリングされないサンプルコードです。

import React, { useRef } from 'react';

function App() {
  // useRefでrefオブジェクト(ここではnumber)を作成し、初期値を10とする
  const number = useRef(10);

  const onButtonClick = () => {
    // refオブジェクト(ここではnumber)の値を更新
    number.current = 20;

    // 設定した値を取り出す
    const value = number.current;

    // コンソールにrefオブジェクト(ここではnumber)を出力
    console.log(`Updated number: ${number.current}`);

    // コンソールに取り出した値(ここではvalue)を出力
    console.log(`value: ${value}`);
  };

  // 画面に表示
  // refオブジェクトの値を更新しても
  // コンポーネントの再レンダリングを引き起こさないため、UI上の表示は初期レンダリング時の値(10)のまま
  return (
    <>
      <p>The number is: {number.current}</p>
      <button onClick={onButtonClick}>refオブジェクトの値を更新</button>
    </>
  );
}

export default App;

上記のサンプルコードについてこれから説明します。

上記のサンプルコードの以下の箇所ではuseRefを用いてnumberという名前のrefオブジェクトを作成しています。refオブジェクトは{current; initialValue}の形式となっており、以下のサンプルコードでは{current: 10}というrefオブジェクトを作成しています。

const number = useRef(10);

上記のサンプルコードの以下の箇所ではrefオブジェクトの値(number.current)を変化させたり、refオブジェクトの値(number.current)を取り出したり、ログに出力したりしています。refオブジェクトの値(number.current)を変化させても再レンダリングは起こりません。

// refオブジェクト(ここではnumber)の値を更新
number.current = 20;

// 設定した値を取り出す
const value = number.current;

// コンソールにrefオブジェクト(ここではnumber)を出力
console.log(`Updated number: ${number.current}`);

useRefでタイマーを管理する

useRefを使うことで再レンダリングを起こさずに値を変化させることができるため、タイマーを管理するのに使うことができます。サンプルコードを以下に示します。

import React, { useRef, useEffect } from 'react';

function App() {
  const intervalRef = useRef();
  useEffect(() => {
    const id = setInterval(() => {
      // タイマーのコード(1秒毎にログ出力している)
      console.log(Date());
    }, 1000);
    intervalRef.current = id;
    return () => {
      clearInterval(intervalRef.current);
    };
  }, []);
  return <div>Timer is running</div>;
}

export default App;

useRefで作成したrefオブジェクト(ここではintervalRef)は、setIntervalによって生成されるタイマーIDを保持するために使われます。

useEffectは第二引数に空の配列[]を渡すことで、コンポーネントがマウントされた後に一度だけ実行されます。この中で、setInterval関数が呼び出し、1秒ごとに指定された処理(ここではログ出力)を実行しています。setIntervalから返されるタイマーIDはrefオブジェクト(ここではintervalRef)のcurrentプロパティに保存しています。

useEffectのクリーンアップ関数(returnで指定された関数)は、コンポーネントのアンマウント時に実行されます。ここではclearInterval関数を使ってタイマーを停止しています。これにより、コンポーネントが不要になった後もタイマーが実行され続けることを防ぎ、メモリリークを避けることができます。

本記事のまとめ

この記事ではReactフックの1つである『useRef』について、以下の内容を説明しました。

  • useRefとは
  • useRefの構文
  • useRefの使い方
    • useRefでDOM要素を参照する方法
    • useRefで値を保存する方法

お読み頂きありがとうございました。