👨‍💻

React + TypeScript | useState と useRef の共通点と相違点

2023/06/22に公開

目的

useRef と useState の共通点と相違点に関して「概念」を簡単に整理した上で、実際にその概念の理解が正しいかどうかをコードベースで確認する場合に、どんなコードを書いて動作確認を実施すればいいのか?という部分までを一貫してまとめたのでその知見を共有することが目的です。

useRef と useState の共通点は?

どちらの Hooks も値を保持することができる

useRef と useState の相違点は?

値が更新されたときに、コンポーネントの再レンダリングが発生するかどうか

上記を踏まえて、どうやって使い分けるのが良い?

コンポーネントの再描画や子コンポーネントの再描画は行いたくないが、内部の値のみ更新したい場合は、値を「useState」で定義するのではなく「useRef」を利用して 状態管理 をする

コンポーネントの再描画や子コンポーネントの再描画は行い、かつ、内部の値も更新したい場合は、値を「useRef」で定義するのではなく「useState」を利用して 状態管理 をする

useRef を使って状態管理を実装する場合

useRef を使って実装した場合、input タグのテキスト欄に文字を入力しても、コンポーネントの再レンダリングは発生しない。更新ボタンをクリックしたら再描画が発生する。

  • テキスト欄に文字を入力した場合
    • コンポーネントの再描画が発生しているかどうかのチェック は出力されない
  • 更新ボタンを押下した場合
    • コンポーネントの再描画が発生しているかどうかのチェック は出力される

サンプルコード

import { useState, useRef } from "react";

export const App = () => {
  const inputEl = useRef<HTMLInputElement>(null);
  const [text, setText] = useState("");

  const handleClick = () => {
    if (inputEl.current === null) return
    setText(inputEl.current.value);
  }

  console.log('コンポーネントの再描画が発生しているかどうかのチェック')

  return (
    <>
      <p>text : {text}</p>
      <input type="text" ref={inputEl}/>
      <button type="button" onClick={handleClick}>更新ボタン</button>
    </>
   );
};

useState を使って状態管理を実装する場合

useState を使って実装した場合、input タグのテキスト欄に文字を入力する度にコンポーネントの再レンダリングが発生する。更新ボタンをクリックしても再描画が発生する。

  • テキスト欄に文字を入力した場合
    • コンポーネントの再描画が発生しているかどうかのチェック は出力される
  • 更新ボタンを押下した場合
    • コンポーネントの再描画が発生しているかどうかのチェック は出力される

サンプルコード

import { useState } from "react";

import type { ChangeEvent } from 'react';

export const App = () => {
  const [value, setValue] = useState("");
  const [text, setText] = useState("");

  const handleChange = (e: ChangeEvent<HTMLInputElement>) => {
    setValue(e.currentTarget.value)
  }

  const handleClick = () => {
    setText(value);
  }

  console.log('コンポーネントの再描画が発生しているかどうかのチェック')

  return (
    <>
      <p>text : {text}</p>
      <input type="text" value={value} onChange={handleChange}/>
      <button type="button" onClick={handleClick}>更新ボタン</button>
    </>
  );
};

参考文献

Discussion