Reactにおいてフックとは、開発者がクラスコンポーネントを必要とせずにReactのstateやその他の機能を使用できるようにする特別な機能です。フックの中でもuseRef
フックは、値を管理したり、DOM(Document Object Model)要素にアクセスしたりするための貴重な機能として際立っています。
useRef
フックは計り知れない柔軟性と可能性をもたらす強力なものですが、多くの開発者がこれの使い方を誤解しています。
この記事では、useRef
フックを深掘りし、その目的、機能、ベストプラクティスを明らかにしたいと思います。この記事を読み終える頃には、フックの本質を理解し、その可能性を効果的に活用する方法について洞察を獲得できているはずです。
useRefフックとは
useRef
フックの主な目的は、更新されても再レンダリングが発生しないような(変更可能な)値を保存することと、DOM要素への参照を保存することの2つです。このフックがどのように動作するのか、もう少し詳しく見てみましょう。
Reactでコンポーネントがレンダリングされると、その状態(state)やその他の変数は通常リセットされます。しかし、コンポーネントを再レンダリングしても特定の値を保持する必要がある場合があります。そのような状況で、useRef
フックが活躍します。これにより、レンダリング間で永続するかたちで値を参照し、コンポーネントの他の部分が変更されても値がそのまま残るようにすることができます。
さらに、useRef
フックは、DOM要素の操作にも有用です。Reactでは、DOM要素に直接アクセスしたり変更したりすることは、特にuseRef
フックなしでは困難です。useRef
を使えば、特定のDOM要素への参照を取得し、その要素に対して操作を行うことができます。これにより、外部ライブラリや複雑な回避策が不要になります。
ReactでuseRefを実装する
ReactプロジェクトでuseRef
フックを使い始めるには、Reactパッケージからインポートします。
import { useRef } from 'react';
インポートしたら、useRef
フックを使用して、関数コンポーネント内でref変数を宣言します。
const myRef = useRef();
これで、myRefというrefオブジェクトが作成され、値の格納やアクセスに使用できるようになります。どの要素でもmyRef
変数を使用するには、その要素のref
propに代入します。
<div ref={myRef}>これは要素の例です</div>
上の例では、div
要素にref
propを代入しています。これにより、コンポーネント内の他の場所でmyRef
変数を使用して要素を参照し、アクセスすることができます。
この参照に格納された値にアクセスするには、myRef
オブジェクトの.current
プロパティを使用します。
const myRefValue = myRef.current;
console.log(myRefValue); // <div>これはサンプルのdivです</div>
useRefフックによるDOM操作
DOMの操作はウェブ開発では一般的な操作です。これによりウェブページの内容や構造、外観を動的に変更したり更新したりすることができます。
従来のJavaScript開発では、DOM要素にアクセスして操作するには、getElementById
、querySelector
、getElementsByClassName
のようなメソッドを使用して、ドキュメントから特定の要素を選択する必要がありました。一度選択すると、コンテンツを更新したり、スタイルを変更したり、イベントリスナーを紐付けたりすることができます。
// HTML
<div>
<input type="text" id="myInput" />
<button id="focusButton">クリックでフォーカス</button>
</div>
// JavaScript
<script>
const inputRef = document.getElementById('myInput');
const focusButton = document.getElementById('focusButton');
const handleFocus = function() {
inputRef.focus();
};
focusButton.addEventListener('click', handleFocus);
</script>
しかし、ReactコンポーネントでDOM要素を扱う場合、コンポーネントの仮想DOMという性質から、そして効率的に更新を行う必要性のため、実際のプロセスは異なります。開発者はしばしば、DOM要素にアクセスし操作するために、参照やjQueryのような外部ライブラリを使用するなど、さまざまなアプローチに頼ることが一般的でした。
そしてReactにuseRef
フックが導入されたことで、コンポーネント内でDOM要素を扱うプロセスが大幅に合理化されています。useRef
フックにより、DOM要素への参照を簡単に作成し、コンポーネントのコンテキスト内で簡単にアクセスして操作できるようになります。
import { useRef } from 'react';
const FocusComponent = () => {
const inputRef = useRef(null);
const handleFocus = () => {
// 入力要素へのアクセス
let inputElement = inputRef.current;
// DOM要素を変更
inputElement.focus();
};
return (
<div>
<input type="text" ref={inputRef} />
<button onClick={handleFocus}>Focus Input</button>
</div>
);
}
この例では、useRef
フックを使用して、input
要素を指す参照としてinputRef
を作成しています。「クリックでフォーカス」ボタンをクリックすると、handleFocus
関数がinputRef.current.focus()
を利用して、入力要素にフォーカスを設定します。これは、useRef
フックが、ReactでDOM要素を扱うプロセスをいかに単純化するかを示す良い例でしょう。
別の例として、ボタンがクリックされたときに背景を変更するというdiv
の操作を行いたいとします。
import { useRef } from 'react';
const ExampleComponent = () => {
const divRef = useRef();
const handleClick = () => {
divRef.current.style.backgroundColor = 'red';
};
return (
<div>
<div ref={divRef}>これはサンプルのdivです</div>
<button onClick={handleClick}>色を変更する</button>
</div>
);
}
この例では、useRef
フックでdivRef
という参照を作成します。この参照をdiv
要素のref
propに割り当てます。
「色を変える」ボタンをクリックすると、handleClick
関数が呼び出されます。この関数では、divRef.current
でdiv
要素にアクセスできます。この場合、style.backgroundColor
プロパティを「red」に変更して、div
要素の背景色を変更します。
divRef.current.style.backgroundColor = 'red';
再レンダリング時の値の保持
再レンダリングをまたいだ値の保持は、useRef
フックの便利な使用例です。再レンダリングをトリガーすることなく、コンポーネントのライフサイクルを通して値を保持する必要がある場合に有益です。
この概念をよく理解するために、実際の例を使ってuseRef
フックとuseState
フックを比較してみましょう。
useStateフックを使った例は以下の通りです。
import { useState } from 'react';
function CounterComponent() {
const [count, setCount] = useState(0);
const increment = () => {
setCount(count + 1);
};
return (
<div>
<p>Count: {count}</p>
<button onClick={increment}>Increment</button>
</div>
);
}
この例では、useState
フックを使って、count
というstate変数を管理しています。increment
関数が呼ばれるたびに、setCount
を使ってcount
の状態が更新されます。これにより、コンポーネントの再レンダリングがトリガーされ、更新後のcount
の値が反映されます。
useRef
フックを使った例は以下の通りです。
import React, { useRef } from 'react';
function CounterComponent() {
const countRef = useRef(0);
const increment = () => {
countRef.current = countRef.current + 1;
console.log('Count:', countRef.current);
};
return (
<div>
<p>Count: {countRef.current}</p>
<button onClick={increment}>Increment</button>
</div>
);
}
この例では、useRef
フックを使って、初期値0
で初期化された変数countRef
を作成しています。increment
関数が呼ばれるたびに、再レンダリングをトリガーすることなく、countRef.current
の値を直接変更します。変更した後の値はコンソールに記録されます。
useRef
フックを使用すると、countRef.current
の値が変更されてもコンポーネントの再レンダリングは行われません。これは、値を変更する必要があるもののレンダリング処理には影響を及ぼしたくないという状況で効果を発揮します。
この方法でuseRef
フックを使用すると、ref
値の変更は自動で再レンダリングをトリガーしませんのでこの点にはご注意ください。更新した値をUIに反映させる必要がある場合は、手動で変更を処理するか、useRef
フックを他のフックやstate変数と組み合わせることができます。
まとめ
この記事では、ReactのuseRef
フックについて説明し、その目的、実装、実際の用途を扱いました。またDOM要素へのアクセスや変更、値の保持にuseRef
を使用する方法をご紹介しました。
useRef
フックのベストプラクティスは、使いすぎないことです。DOM要素へのアクセスや操作、再レンダリング時の値の保持が特に必要な場合に使用するようにしてください。
useRef
フックには、アニメーションやトランジション、値や中間結果のキャッシュなど、Reactアプリケーションを際立たせるさまざまな実用的な用途があります。
次のReactアプリケーション構築の際には、Kinstaのアプリケーションホスティングを無料でデプロイにお試しください。
あなたはuseRefフックについてどう思いますか?以下のコメント欄でお聞かせください。