LoginSignup
0
0

More than 1 year has passed since last update.

React useRef()を利用して再レンダリングを防ぐ

Posted at

useRef()

useRef()とは参照を行うためのフックであり、主にDOMへのアクセスに利用されます。
useRef()は、コンポーネント内において変数に値を保持することができ、値を更新してもコンポーネントが再レンダリングされることはありません。

useRef()とuseState()の違い

  • 共通点
    互いに値を保持することができる

  • 相違点
    useRef()は値が更新されてもコンポーネントの再レンダリングは行われない
    useState()は値が更新されるとコンポーネントの再レンダリングが行われる

成果物

 useRef()useState()との違いを以下のサンプルを元にして解析します。

コード解析

index.js

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

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.currentinputタグが入っていることが確認できる。
inputRefObject.current.focusが実行されると、先ほど取得したinputタグがフォーカスされた状態になる。

App.js
  const sampleButton = () => {
    console.log(inputRefObject.current); // <input type="text"></input>

    // ref={inputRefObject}が書かれているinputタグをフォーカスする
    inputRefObject.current.focus();
  };

// 省略

<input ref={inputRefObject} type="text" />

サンプルコードを用いたuseRef()の動き

useRef()

下記がuseRef()に関するコードであり、以下の流れで動作します。

  1. <input ref={inputRefObject} type="text" />に入力されたテキストをinputRefObject.current.valueで取得する。
    inputRefObject.cerrent.value = <input type="text" value="フォームに入力されている文字" /> = 「フォームに入力されている文字」が成り立ちます

  2. <button onClick={handleClick}>set text</button>を押すと、inputRefObject.cerrent.valueを状態変数textに渡す

  3. textに渡されたinputRefObject.cerrent.valueを画面に表示する

今回、useEffect()の第2関数には依存配列が渡されていないため、コンポーネントがレンダリングされる度に「レンダリングされました!」と表示されます。
入力フォームにテキストを入力、または削除しても「レンダリングされました!」と表示されていないことが確認できると思います。しかし、「set text」ボタンを押すと、入力フォームに入力された内容がそのまま出力されていることが確認できると思います。
つまり、inputRefObject.cerrent.valueは更新されていますが、画面のコンポーネントは再レンダリングされていないことが分かります。

App.js
  const handleClick = () => {
    setText(inputRefObject.current.value);
  };

// 省略

<h3>text:{text}</h3>

<input ref={inputRefObject} type="text" />

<button onClick={handleClick}>set text</button>
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0