useRef()
useRef()
とは参照を行うためのフックであり、主にDOMへのアクセスに利用されます。
useRef()
は、コンポーネント内において変数に値を保持することができ、値を更新してもコンポーネントが再レンダリングされることはありません。
useRef()とuseState()の違い
-
共通点
互いに値を保持することができる -
相違点
useRef()
は値が更新されてもコンポーネントの再レンダリングは行われない
useState()
は値が更新されるとコンポーネントの再レンダリングが行われる
成果物
useRef()
とuseState()
との違いを以下のサンプルを元にして解析します。
コード解析
index.js
import { createRoot } from "react-dom/client";
import App from "./App";
const rootElement = document.getElementById("root");
const root = createRoot(rootElement);
root.render(<App />);
App.js
// useRefを使用するためにimportする
import React, { useRef, useState, useEffect } from "react";
import "./styles.css";
const SampleComponent = () => {
// input要素への参照オブジェクトinputRefObjectを作成
// useRef()の引数に渡した値は、refObjectのcurrentプロパティの値になります
// 今回の場合、useRef()の引数にはnullが渡されているので、
// inputRefObject.currentの初期値はnullになる
const inputRefObject = useRef(null);
// 現在のフォームに入力されている状態変数text
// textを更新する関数setText
const [text, setText] = useState("");
// useEffect()は関数の実行タイミングを、コンポーネントのマウント後、アンマウント後、
// または更新後まで遅らせることができるフック
// 第2引数に渡された依存配列の要素によって関数の実行タイミングを制御する
// 今回の場合、第2引数には依存配列が渡されていないため、
// コンポーネントがレンダリングされるたびに「レンダリングされました!」と表示される
useEffect(() => console.log("レンダリングされました!"));
// inputフォームをフォーカスする関数sampleButtonを定義する
const sampleButton = () => {
console.log(inputRefObject.current);
// ref={inputRefObject}が設定されているinputフォームをフォーカスする
inputRefObject.current.focus();
};
// inputフォームに入力された値を状態変数textnに設定する関数handleClickを定義する
const handleClick = () => {
setText(inputRefObject.current.value);
};
// 入力フォームに設定されたテキスをリセットする関数textResetを定義する
const textReset = () => {
setText("");
inputRefObject.current.value = "";
};
return (
<>
<h3>text:{text}</h3>
<div>
// ref属性でinputRefObjcetとinput要素を紐づける
<input ref={inputRefObject} type="text" />
// ボタンを押すと入力フォームがフォーカスされます。
<button onClick={sampleButton}>focus</button>
// ボタンを押すと関数handleClickが実行される
<button onClick={handleClick}>set text</button>
</div>
</>
);
};
export default function App() {
return <SampleComponent />;
}
入力フォームをフォーカスする
input
タグにref
属性inputRefObject
を指定した場合、inputRefObject.current
にinput
タグが入っていることが確認できる。
inputRefObject.current.focus
が実行されると、先ほど取得したinput
タグがフォーカスされた状態になる。
const sampleButton = () => {
console.log(inputRefObject.current); // <input type="text"></input>
// ref={inputRefObject}が書かれているinputタグをフォーカスする
inputRefObject.current.focus();
};
// 省略
<input ref={inputRefObject} type="text" />
サンプルコードを用いたuseRef()の動き
useRef()
下記がuseRef()に関するコードであり、以下の流れで動作します。
-
<input ref={inputRefObject} type="text" />
に入力されたテキストをinputRefObject.current.value
で取得する。
inputRefObject.cerrent.value
=<input type="text" value="フォームに入力されている文字" />
=「フォームに入力されている文字」
が成り立ちます -
<button onClick={handleClick}>set text</button>
を押すと、inputRefObject.cerrent.value
を状態変数text
に渡す -
textに渡された
inputRefObject.cerrent.value
を画面に表示する
今回、useEffect()の第2関数には依存配列が渡されていないため、コンポーネントがレンダリングされる度に「レンダリングされました!」と表示されます。
入力フォームにテキストを入力、または削除しても「レンダリングされました!」と表示されていないことが確認できると思います。しかし、「set text」ボタンを押すと、入力フォームに入力された内容がそのまま出力されていることが確認できると思います。
つまり、inputRefObject.cerrent.value
は更新されていますが、画面のコンポーネントは再レンダリングされていないことが分かります。
const handleClick = () => {
setText(inputRefObject.current.value);
};
// 省略
<h3>text:{text}</h3>
<input ref={inputRefObject} type="text" />
<button onClick={handleClick}>set text</button>