本記事ではReact Hooksの一つのuseRef()について使い方から、useState()との違いまで詳細に解説しました。
少しでも皆さんの理解につながれば嬉しいです。
では早速解説を始めていきます。
useRefはコンポーネント内での参照を管理する
useRef()はReact Hooksの一つで、コンポーネント内での参照を管理するために使用されます。
大きな特徴としてuseRef()を使用することで、コンポーネントの中身が変更されても再レンダリングすることなく値を保持することができます。
これだけではなかなか理解できないと思うので実装例を見ながら学んでいきましょう!
どんな実装ができるのか?
例えば、フォームに入力したテキストを送信ボタンを押した時に表示させる時に使えます。こんな感じです↓
ソースコードはこちらです。(以降の解説はこのソースコードをもとに解説していきます)
import React, { useState, useRef } from 'react';
import './ReactDev.css';
const ReactDev = () => {
const enteredTitle = useRef();
const [title, setTitle] = useState();
const addList = (e) => {
e.preventDefault(e);
const data = enteredTitle.current.value;
setTitle(data);
};
return (
<div className="container">
<form onSubmit={addList}>
<label htmlFor="type"></label>
<input id="type" type="text" ref={enteredTitle} />
<button type="submit">Add List</button>
</form>
<div>
<h2>{title}</h2>
</div>
</div>
);
};
export default ReactDev;
useRefの実装方法は下記の順に行います。
- useRefをインポートする
- コンポーネント内にuseRefを記述する
- JSX内に②と紐付ける「ref」を設定する
- currentプロパティを操る
それぞれ解説していきます。
①useRefをインポートする
ソースの1行目でuseRefをインポートします。(※今回の実装上useStateもインポートしています)
import React, { useState, useRef } from 'react';
②コンポーネント内にuseRefを記述する
ソースの5行目でuseRef()を変数に入れ込みます。
const enteredTitle = useRef();
③JSX内に②で設定した変数名と同じ名前を「ref」につけてuseRefと紐付けます
<input id="type" type="text" ref={enteredTitle} />
④currentプロパティを操る
ソースの10行目でcurrentプロパティを使います。ここが重要です。
const data = enteredTitle.current.value;
一体currentプロパティとは何でしょう?
currentプロパティはDOMノードが保存される箱
useRef()はcurrentプロパティを使ってDOMを操作します。
currentプロパティとはrefで紐付けた要素のDOMノードが保存される箱です。
実際に箱の中身を見てみましょう。
const ReactDev = () => {
const enteredTitle = useRef();
console.log(enteredTitle);
ー略ー
return (
ー略ー
<input id="type" type="text" ref={enteredTitle} />
ー略ー
);
};
const enteredTitle = useRef();
このように記述すると下図の情報が返ってきます。(画像は一部で下にもっと続きます)
これらは紐付けたinputタグのDOMノード情報です。
この結果から、currentプロパティを通してDOM情報を操り要素の値、高さ、横幅、クラス名,,,, など変更できるのです。
今回の実装例ではinputタグに打ち込まれたテキストの値を取得したいので「current.value」を使っています。
useRefとuseStateの違いは?
「フォームにテキストを入力してその内容を出力する」のであればuseState()でも実装可能です。
実際どちらを使っても問題はないです。
ではuseRef()とuseState()は何が違うのでしょう?
ざっくりとまとめると下記の違いがあります。
useRef | useState | |
管理対象 | コンポーネントでの参照 | コンポーネントの内部状態 |
レンダリング | なし | あり |
useState()はコンポーネントの内部状態を管理するために使用され、値が変更された場合に再レンダリングをトリガーします。
一方、useRef()はコンポーネント内で参照可能な値を管理するために使用され、値が変更されても再レンダリングをトリガーしません。
要はコンポーネント内の値が変わった時にレンダリングされるのがuseState()、レンダリングされないのがuseRef()と覚えておけば大丈夫です。
では実際にそれぞれで実装して結果を比較してみましょう。
useRefで実装した時のレンダリング
const ReactDev = () => {
const enteredTitle = useRef();
const [title, setTitle] = useState();
const addList = (e) => {
e.preventDefault(e);
const data = enteredTitle.current.value;
setTitle(data);
};
console.log('レンダリングしました!');
return (
<div className="container">
<form onSubmit={addList}>
<input type="text" ref={enteredTitle} />
<button type="submit">Add List</button>
</form>
<div>
<h2>{title}</h2>
</div>
</div>
);
};
「レンダリングしました!」の文字の出力は1回だけでした。
ちなみにこの「レンダリングしました!」は3行目で設定したuseState()が8行目のsetTitle()が実行されることによってコンポーネントが再レンダリングされたために出てきたのであってuseRef()が再レンダリングをさせているのではありません。
useStateで実装した時のレンダリング
const ReactDev = () => {
const [inputTitle, setInputTitle] = useState();
const [title, setTitle] = useState();
const titleAdd = (e) => {
setInputTitle(e.target.value);
};
const addList = (e) => {
e.preventDefault(e);
setTitle(inputTitle);
};
console.log('レンダリングしました!');
return (
<div className="container">
<form onSubmit={addList}>
<input type="text" onChange={titleAdd} />
<button type="submit">Add List</button>
</form>
<div>
<h2>{title}</h2>
</div>
</div>
);
};
今回は合計7回の「レンダリングしました!」が出力されました。
内訳はテキスト入力で6回、最後のボタンクリックで1回のレンダリングが起こっています。
これはinputの値を変更をuseState()で監視し続けているためにキーボードで打ち込むたびにsetInputTitle()が発火し、毎回コンポーネントを再レンダリングされてしまうのです。
このようにuseRef()とuseState()では最終のアウトプットの形は同じですが、レンダリング回数の違いが発生します。
どちらと使うべきかは状況によって異なりますが、今回の例であればuseRef()の方がレンダリング回数を抑えられてWebパフォーマンスの最適化ができそうです。
useState()は文字数をチェックさせて入力時にエラーの有無を監視させる時に使うのが良さそうです。
最後に
今回はuseRef()の解説をしました。
少しでもこれからプログラミングを学ぼうと考えている方の為になる発信をできれば思いますので、温かい目で見てもらえると嬉しいです。
私がReactを学んでいるUdemyの講座が下記です。48時間と長いですが基本から応用までかなり解説してくれているので興味があればぜひチェックしてみてください😌
ベストセラー取得