5
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

ARアドバンストテクノロジ株式会社(ARI) Advent Calendar 2024

Day 24

useState, useRef, useMemo って結局何を使えばいいの?使い分け方を整理してみよう。

Last updated at Posted at 2024-12-23

はじめに

React の開発で変数を扱うときによく出てくる、 useState, useRef, useMemo
基本的には useState を使うことが多いですが、コードが複雑になってくると使い分けた方がより良いケースというのも増えてきます。
最近ちょうど使い分けを意識する状況がいくつかあったので、改めて学び直してみることにしました。

この記事では、これらの Hook の特徴を整理し、具体的な使い方や実践例を紹介します。

対象読者

  • React を既に使ったことがある人
    基本的な概念は理解しており、次のステップに進みたい方。

  • React の効率的なコード設計を学びたい人
    より複雑なアプリケーションでパフォーマンスを向上させたい方。

  • React Hooks の実践的な使い分けを知りたい人
    特定のシチュエーションで、どの Hook を使えばよいか迷ったことがある方。

1. useState の特徴と具体例

主な特徴

useState は、コンポーネントに state変数 を追加するための Hook です。
コンポーネント内で値(状態)を管理 し、管理する値が変化するとコンポーネントが再レンダリングされ、UI に反映されます。

具体例: ボタンをクリックしたときにカウントアップする

import { useState } from 'react';

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

  return (
    <div>
      <p>現在のカウント: {count}</p>
      <button onClick={() => setCount(count + 1)}>+1</button>
    </div>
  );
}

補足: 不適切な使用ケース

  • 頻繁に変化する値(例: マウス座標やスクロール位置)の管理
    再レンダリングが多発し、パフォーマンスが低下します。この場合は useRef を使用するのが適切です。

2. useRef の特徴と具体例

主な特徴

useRef は、レンダー時には不要な値を参照するための Hook です。
状態に影響を与えない値や DOM 要素を参照するために用いられ、値が変更されても再レンダリングは発生しません。

具体例: テキスト入力欄にフォーカスを当てる

import { useRef } from 'react';

function InputFocus() {
  const inputRef = useRef<HTMLInputElement>(null);

  const handleFocus = () => {
    if (inputRef.current) {
      inputRef.current.focus();
    }
  };

  return (
    <div>
      <input ref={inputRef} type="text" placeholder="ここに入力" />
      <button onClick={handleFocus}>フォーカスを当てる</button>
    </div>
  );
}

補足: 不適切な使用ケース

  • UI 表示に必要な値の管理
    useRef は再レンダリングをトリガーしないため、UI に影響を与える値(例: カウンターの状態)を管理するには不適切です。その場合は useState を使用してください。

3. useMemo の特徴と具体例

主な特徴

useMemo は、レンダー間で計算結果をキャッシュするための Hook です。
計算コストの高い処理をキャッシュし、効率化するための依存配列が変わらない限り再計算をスキップします。

具体例: 検索クエリに応じてリストをフィルタリング

import { useState, useMemo } from 'react';

function FilterList({ items }: { items: string[] }) {
  const [query, setQuery] = useState('');

  const filteredItems = useMemo(() => {
    console.log('フィルタリング処理が実行されました');
    return items.filter(item => item.includes(query));
  }, [items, query]);

  return (
    <div>
      <input
        type="text"
        value={query}
        onChange={(e) => setQuery(e.target.value)}
        placeholder="検索"
      />
      <ul>
        {filteredItems.map((item, index) => (
          <li key={index}>{item}</li>
        ))}
      </ul>
    </div>
  );
}

補足: 不適切な使用ケース

  • 計算コストが低い処理のキャッシュ
    単純な処理(例: 配列の長さを計算するなど)に useMemo を使うと、かえってコードが冗長になり可読性が低下します。
  • 値の更新が useMemo の範囲外で必要な場合
    useMemo はキャッシュ専用の仕組みであり、値を動的に更新する仕組みはありません。そのため、値の更新をリアクティブに管理したい場合は useState を使用する必要があります。

使い分けのポイントまとめ

ここまでの説明をまとめました。

Hook 適切な用途 不適切な用途
useState UI に影響を与える状態の管理 再レンダリング不要な値や頻繁な更新が必要な値
useRef 値の参照や DOM 要素の操作 UI 表示に必要な値の管理
useMemo 計算コストの高い処理のキャッシュ コストが低い処理、または値の更新が必要な場合

使い分けを考える上で「適切な用途」を押さえておくことは前提として大事ですが、「不適切な用途」にあたる「どんな時は使えないのか、なぜならば...」を把握することも、より納得した選択をとるために大事だなと思います。

終わりに

Hook の違いがイマイチ理解できてないな...という自分のモヤモヤを出発点に、今回の記事を作ってみましたが、いかがだったでしょうか?

私は、理解が特に足りていなかった useRef と、それぞれの不適切な使用シーンを整理できたことで、今後実装していく上での判断基準がより明確になったな。という収穫を感じました。

あなたにとっても、何か役立つ要素があったら幸いです。
ここまで読んでいただき、ありがとうございました!

参考リンク

5
2
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
5
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?