NU:LOGiC Logo

【React.js】useRefの使い方と注意点まとめ|useStateの違い、使い分け方も解説!

【React.js】useRefの使い方と注意点まとめ|useStateの違い、使い分け方も解説!

Reactのフックの中でも、useRefは多くの実践的なシチュエーションで必要とされます。例えば、フォームの特定のフィールドに自動でフォーカスを当てたい、アニメーションの途中経過を制御したい、またはコンポーネントの以前の状態を追跡したい場合など、useRefが役立つケースは数多く存在します。この記事では、そんなuseRefの基本から応用まで、具体的なコード例とともにその使い方をわかりやすく解説します。実際の開発現場で直面するような問題を効果的に解決するための手助けとなれば幸いです。

3行で要約すると

  • useRefはReactのフックで、DOM参照や変数の値の保持に利用される。
  • useRefuseStateの違いは、値の変更がコンポーネントの再レンダリングを引き起こすかどうか。
  • useRefの活用は多岐にわたるが、再レンダリングの影響やDOMのマウントタイミングに注意が必要。

「useRef」の基本的な使い方

「useRef」とは?

useRefはReactのフックの一つで、DOM要素への参照や、レンダリング間で変数の値を維持するために使用されます。一番の特徴は、useRefが返すオブジェクトの.currentプロパティを更新してもコンポーネントが再レンダリングされない点です。例えば、特定のDOM要素にフォーカスを当てたい場面などに使います。

import React, { useRef, useEffect } from 'react';

function TextInputWithFocusButton() {
  const inputEl = useRef(null);

  const onButtonClick = () => {
    // `current` はテキスト入力のDOM要素を指します
    inputEl.current.focus();
  };

  return (
    <>
      <input ref={inputEl} type="text" />
      <button onClick={onButtonClick}>フォーカスを当てる</button>
    </>
  );
}

このコードでは、ボタンをクリックするとテキスト入力エリアにフォーカスが当たるようにしています。ここでのポイントは、useRefを使ってinput要素への参照を取得している点です。

「useRef」の使用例3パターン

フォームの入力内容の取得

時々、フォームの入力内容を直接取得したい場面があります。useRefを使用することで、直接DOM要素にアクセスしてその値を取得することができます。

import React, { useRef } from 'react';

function FormComponent() {
  const inputRef = useRef(null);

  const handleSubmit = () => {
    alert('入力内容は: ' + inputRef.current.value);
  };

  return (
    <>
      <input ref={inputRef} type="text" />
      <button onClick={handleSubmit}>内容を表示</button>
    </>
  );
}

アニメーションの制御

useRefは、アニメーションの制御など、特定のDOM要素の状態やプロパティを直接操作したい場合にも役立ちます。

import React, { useRef, useEffect } from 'react';

function AnimatedComponent() {
  const boxRef = useRef(null);

  useEffect(() => {
    boxRef.current.style.transition = 'all 0.5s';
    boxRef.current.style.transform = 'translateX(100px)';
  }, []);

  return <div ref={boxRef} style={{ width: '100px', height: '100px', background: 'red' }}></div>;
}

イベントリスナーの追加

外部ライブラリや、特定のイベントを処理する際に、DOM要素に直接イベントリスナーを追加したい場合にuseRefを活用することができます。

import React, { useRef, useEffect } from 'react';

function EventListenerComponent() {
  const buttonRef = useRef(null);

  useEffect(() => {
    const handleAlertClick = () => {
      alert('ボタンがクリックされました!');
    };

    buttonRef.current.addEventListener('click', handleAlertClick);

    return () => {
      buttonRef.current.removeEventListener('click', handleAlertClick);
    };
  }, []);

  return <button ref={buttonRef}>クリックしてみてください</button>;
}

この例では、useRefを使用してボタン要素への参照を取得し、そのボタンに対してイベントリスナーを追加しています。

「useRef」と「useState」

「useState」とは?

useStateはReactのもう一つの基本的なフックで、コンポーネントの状態を管理するために使用されます。このフックを使うことで、コンポーネント内で変数の値を保持し、その変数の値が変更されたときにコンポーネントを再レンダリングすることができます。

import React, { useState } from 'react';

function Counter() {
  const [count, setCount] = useState(0);

  return (
    <>
      <p>カウント: {count}</p>
      <button onClick={() => setCount(count + 1)}>増加</button>
    </>
  );
}

このコードでは、useStateを使用してカウンターの状態を管理しています。ボタンをクリックするたびにカウンターの値が増加します。

「useRef」と「useState」の違い

useRefuseStateは、変数の値をコンポーネント間で保持する点では似ていますが、いくつかの重要な違いがあります。

  1. useRefが返すオブジェクトの.currentプロパティを更新してもコンポーネントは再レンダリングされませんが、useStateのセッター関数を使用して状態を更新すると、コンポーネントは再レンダリングされます。
  2. useRefはDOM要素への直接的な参照を保持するためにも使用されますが、useStateはそのような目的には使用されません。
// useRefの例
const inputRef = useRef(null);
inputRef.current.focus();  // コンポーネントは再レンダリングされない

// useStateの例
const [text, setText] = useState('');
setText('新しいテキスト');  // コンポーネントが再レンダリングされる

この違いを理解することで、それぞれのフックがどのような場面で最も役立つのかを判断することができます。

「useRef」を使用する際の注意点

不要な再レンダリングを防ぐ

useRefは、その.currentプロパティを更新してもコンポーネントの再レンダリングを引き起こさないため、不必要な再レンダリングを避けるのに役立ちます。しかし、これを過度に使用すると、コンポーネントの挙動が予期しないものになる場合があります。例えば、useRefの値の変更をトリガーとして何らかの処理を行いたい場合、その変更が再レンダリングを引き起こさないため、予期しないバグが発生する可能性があります。

const countRef = useRef(0);

const increment = () => {
  countRef.current += 1;
  // この変更は再レンダリングを引き起こさない
};

DOM要素がまだマウントされていない可能性

useRefでDOM要素への参照を取得する場合、そのDOM要素がまだマウントされていないタイミングで参照を使用しようとするとエラーが発生します。特に、コンポーネントのレンダリングが完了する前や、条件付きでレンダリングされる要素にuseRefを適用する場合に注意が必要です。

const myElementRef = useRef(null);

if (myElementRef.current) {
  // myElementRef.currentがnullでない場合のみ操作を行う
  myElementRef.current.doSomething();
}

useRefの不変性

useRefは、その生存期間中に保持する参照が変更されないことを保証します。これは、同じrefオブジェクトを複数のレンダリング間で安全に使用できることを意味します。しかし、.currentプロパティ自体は変更可能であるため、注意して操作する必要があります。

「useRef」の使い方まとめ

Reactのフックの中でも特に多用されるuseRefは、その柔軟性と機能性から多岐にわたる場面での活用が期待されます。

  • 基本的な使い方: DOM要素への直接的な参照や、レンダリング間での変数の値の保持に適しています。
  • 使用例: フォームの入力内容の取得、アニメーションの制御、イベントリスナーの追加など、さまざまな使用ケースがあります。
  • 他のフックとの関連: useStateとは異なり、useRefは値の変更がコンポーネントの再レンダリングを引き起こさないという特性があります。この違いを理解することで、それぞれのフックの適切な使用場面を見極めることができます。
  • 注意点: useRefを使用する際には、不要な再レンダリングを防ぐことや、DOM要素がまだマウントされていないタイミングでのエラーを回避することなど、いくつかの注意点が必要です。

この記事を通して、useRefの基本的な使い方や注意点、その他の関連情報を学び、より効果的にReactの開発に取り組む手助けとなれば幸いです。継続的な学びと実践を通じて、Reactの機能を最大限に活用しましょう。