MofuMofu2 / react-sandbox

React.js Sandbox
1 stars 0 forks source link

7-2 さまざまな値への参照を準備する – useRef関数 #67

Closed MofuMofu2 closed 10 months ago

MofuMofu2 commented 10 months ago

https://react.dev/reference/react/useRef

汎用してはいけませんと説明があるけど、いけないなら最初の例で出さない方がいいのではと思った。 なんかこれを使わなきゃいけない気分になる。

React.jsの仕組みから離れた形で値を操作するならなんでこれがあるのか謎 🤔

MofuMofu2 commented 10 months ago

useStateとuseRefの違いは再レンダリングされるかどうか。 useStateはVueのdataみたいに値が変わると再レンダリングされる。useRefはされない。 再レンダリングされない状態を持つのはどういうシチュエーションなんだろうか。


useRefを使う例を教えてください。状態が変わっても再レンダリングされないのであれば、あまり意味がないと思ってしまいます。普段はuseStateを使えばいいと思いました。

答え

useRef を使う主な理由は、コンポーネントのレンダリングに影響を与えずに、コンポーネントのライフサイクル全体で値を保持したい場合です。確かに、多くの状況では useState や他の state 管理手法が適していますが、useRef は特定の用途にとても便利です。以下に、useRef の使用例をいくつか紹介します。

React で特定の DOM 要素にアクセスする必要がある場合に useRef を使用します。例えば、フォーカスを自動的に設定したり、要素のサイズを取得したりする場合です。

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

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

  const onButtonClick = () => {
    // `current` プロパティは、マウントされた `input` DOM 要素を指します。
    inputEl.current.focus();
  };

  return (
    <>
      <input ref={inputEl} type="text" />
      <button onClick={onButtonClick}>Focus the input</button>
    </>
  );
}

useRef はレンダリング間で値を保持するのにも使えます。これは、値が変わってもコンポーネントが再レンダリングされないため、パフォーマンスの最適化に役立ちます。

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

function TimerComponent() {
  const intervalRef = useRef();

  useEffect(() => {
    const id = setInterval(() => {
      // 何かの処理
    }, 1000);
    intervalRef.current = id;
    return () => clearInterval(intervalRef.current);
  }, []);

  // 他のロジック
}

useRef を使用して、以前の state や props の値を保持できます。これは、現在の値と以前の値を比較する必要がある場合に特に便利です。

なるほど、これはありうるなと思った。「以前から変わってたら更新できる」みたいなロジックを組みやすい。

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

function ExampleComponent({ someProp }) {
  const prevProp = useRef();

  useEffect(() => {
    prevProp.current = someProp;
  });

  // 以前のプロップスと現在のプロップスを比較するロジック
}

これらの例は useRef のいくつかの一般的な使用法を示していますが、このフックは非常に汎用性が高いため、他にも多くの用途があります。基本的には、レンダリングに影響を与えることなく、コンポーネント間で値を「保持」する必要がある場合に考慮すると良いでしょう。

MofuMofu2 commented 10 months ago

APIレスポンスパラメータを取得し、1回だけPropsしたのちはずっと値が変わらないみたいな状況の場合、useStateではなくuseRefに保存してPropsするといいというイメージですか?

はい、その理解は正しいです。useState は状態が変更されるたびにコンポーネントを再レンダリングしますが、useRef はそのような動作をしません。したがって、APIからのレスポンスのように一度取得した後に変更されないデータを扱う場合、useRef を使用することが適切な選択肢となることがあります。

useStateuseRef の比較

実際の例

APIからデータを取得し、そのデータがコンポーネントのライフサイクル中で変わらない場合、useState ではなく useRef を使用する方が効率的です。これにより、不要な再レンダリングを避け、パフォーマンスを向上させることができます。

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

function MyComponent({ apiData }) {
  const dataRef = useRef(apiData);

  useEffect(() => {
    // API レスポンスを useRef で保存
    dataRef.current = apiData;
  }, []); // 空の依存配列で初期マウント時のみ実行

  // dataRef.current を使用して何か処理を行う
}

この例では、useEffect を使用して初期マウント時に一度だけ API データを useRef に保存し、その後はこのデータが変わらない限り再レンダリングされません。これにより、不変のデータを効率的に扱うことができます。


なるほどね〜。初期レンダリング後にPropsした値をセットして…みたいなときはよく試した方が良さそうだな。

MofuMofu2 commented 10 months ago

あれか、更新のときに「キャンセルで編集した値になっちゃう!」みたいなのを避けるにはuseStateじゃなくてuseRefを使わないとダメなのか。なるほどな。

MofuMofu2 commented 10 months ago

更新のタイミングを決めるのは依存配列っていうのはuseXXX系みんな共通なのかもね。 https://react.dev/reference/react/useImperativeHandle

MofuMofu2 commented 10 months ago

useRefの使い所があまりわからないなあ。自由に操作できるのを防ぎたいんだろうけど、自由に操作したくないパターンがあまり思いつかない。なんかあるのかな。