React 速習チュートリアル

React useRef Hook

1. useRef

useRef フックは、レンダリング間で値を保持(永続化)することを可能にします。
更新されても再レンダリングを発生させない ミュータブル(可変)な値 を保存するために使用できます。
また、DOM要素に直接アクセスするためにも利用されます。

1.1 再レンダリングを発生させない

もし useState フックを使ってアプリケーションのレンダリング回数をカウントしようとすると、そのフック自体が再レンダリングを誘発するため、無限ループに陥ってしまいます。
これを回避するために、useRef フックを使用できます。

実装例:useRef を使用してアプリケーションのレンダリング回数を追跡します。

import { useState, useRef, useEffect } from 'react';
import { createRoot } from 'react-dom/client';

function App() {
  const [inputValue, setInputValue] = useState("");
  // 初期値を0でリファレンスを作成
  const count = useRef(0);

  useEffect(() => {
    // current値を更新しても再レンダリングは発生しない
    count.current = count.current + 1;
  });

  return (
    <>
      <p>インプットフィールドに入力してください:</p>
      <input
        type="text"
        value={inputValue}
        onChange={(e) => setInputValue(e.target.value)}
      />
      <h1>レンダリング回数: {count.current}</h1>
    </>
  );
}

createRoot(document.getElementById('root')).render(
  <App />
);

useRef() は1つのアイテムのみを返します。それは current と呼ばれる オブジェクト です。
useRef を初期化する際、初期値を設定します: useRef(0)
これは const count = {current: 0} と定義しているようなものです。count.current を使うことで、その値にアクセスできます。

2. DOM要素へのアクセス (Accessing DOM Elements)

useRef フックは、DOM要素に直接アクセスするためによく使われます。

手順は以下の通りです:

  1. まず、useRef フックを使ってRef(リファレンス)を作成します: const inputElement = useRef();
  2. 次に、JSX内の ref 属性を使って、DOM要素にそのRefを紐付けます: <input type="text" ref={inputElement} />
  3. 最後に、current プロパティを使ってDOM要素にアクセスします: inputElement.current

実装例:useRef を使ってインプットにフォーカスを当てます。

import { useRef } from 'react';
import { createRoot } from 'react-dom/client';

function App() {
  const inputElement = useRef();

  const focusInput = () => {
    // DOMのfocusメソッドを直接呼び出す
    inputElement.current.focus();
  };

  return (
    <>
      <input type="text" ref={inputElement} />
      <button onClick={focusInput}>インプットにフォーカス</button>
    </>
  );
}

createRoot(document.getElementById('root')).render(
  <App />
);

この例では、ボタンがクリックされると onClick 関数が inputElement.current.focus() を呼び出すため、インプットフィールドにフォーカスが当たります。

3. ステート変更の追跡

useRef フックは、以前のステート値 を保持するためにも使用できます。
これは、useRef の値がレンダリングを跨いでも保持(永続化)されるためです。

実装例:useRef を使用して一つ前のステート値を保持します。

import { useRef, useState, useEffect } from 'react';
import { createRoot } from 'react-dom/client';

function App() {
  const [inputValue, setInputValue] = useState("");
  const previousInputValue = useRef("");

  useEffect(() => {
    // inputValueが更新された後、currentに現在の値を保存
    // 次回のレンダリング時に「前の値」として参照できる
    previousInputValue.current = inputValue;
  }, [inputValue]);

  return (
    <>
      <input
        type="text"
        value={inputValue}
        onChange={(e) => setInputValue(e.target.value)}
      />
      <h2>現在の値: {inputValue}</h2>
      <h2>一つ前の値: {previousInputValue.current}</h2>
    </>
  );
}

createRoot(document.getElementById('root')).render(
  <App />
);

ここでは、useStateuseEffect、そして useRef を組み合わせて以前のステートを追跡しています。
useEffect 内で、インプットフィールドへの入力により inputValue が更新されるたびに、useRefcurrent 値を更新しています。