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要素に直接アクセスするためによく使われます。
手順は以下の通りです:
- まず、
useRefフックを使ってRef(リファレンス)を作成します:const inputElement = useRef(); - 次に、JSX内の
ref属性を使って、DOM要素にそのRefを紐付けます:<input type="text" ref={inputElement} /> - 最後に、
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 />
);ここでは、useState、useEffect、そして useRef を組み合わせて以前のステートを追跡しています。useEffect 内で、インプットフィールドへの入力により inputValue が更新されるたびに、useRef の current 値を更新しています。