Next.js useState と useRef の違いは?最適な使い分け

React や Next.js を学び始めると、ほぼ必ず登場する useStateuseRef
どちらも値を保持するためのフックですが、内部的な挙動が大きく異なります。

と疑問を感じる人も多いはずです。

本記事では、「初めて触る人でもスッと理解できる」ことを目指して、役割の違い・使い分け・具体例・パフォーマンスの観点までまとめて解説します。


🧩 useState と useRef の違い

まず結論から。

比較ポイント useState useRef
値を変更すると再レンダーされる? される されない
主な用途 UI を変えたい時 内部処理・DOM 操作
値の性質 不変(変更で新レンダー) ミュータブル(自由に書き換え可)
React が監視する? する しない

▼ 一言でまとめると…


🟦 useState とは?(UI のための状態管理)

useState は「UIを更新したい時」に使うフックです。

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

const handleClick = () => {
  setCount(prev => prev + 1); // ← ここで再レンダー
};

◆ 特徴

◆ こんな時に使う

✕ useState を使うべきでないケース

これらは useRef の方が適切です。


🟩 useRef とは?(再レンダーしない “箱”)

useRef は React コンポーネント内で
ミュータブルな値を保持するための「箱」 を提供します。

const countRef = useRef(0);

const handleClick = () => {
  countRef.current += 1; // ← 再レンダーされない
  console.log(countRef.current);
};

◆ 特徴

React はこの値を監視しないため
「内部用の値」「レンダーと関係ないもの」に最適。

◆ よく使う用途


🔥 useRef の方が速いって本当?

✔ 一部のケースで YES
✕ でも常に速いわけではない。

ポイントはこれ:

useRef は「再レンダーが走らない」ため、結果的にパフォーマンスが良いことがある。

具体例を見ればわかります。


❌ NG: 内部値なのに useState を使ってしまう例

const [apiCallCount, setApiCallCount] = useState(0);

const fetchData = async () => {
  setApiCallCount(c => c + 1); // 毎回 UI が再レンダーされてしまう
};

UI に表示しないのに再レンダーはムダです。

✔ OK: useRef を使うべき

const apiCallCountRef = useRef(0);

const fetchData = async () => {
  apiCallCountRef.current++; // これで良い
};

無駄な再レンダーが発生しない → 結果的に高速。


🧭 “どちらを使う?” チェックリスト

▼ useState が適切

▼ useRef が適切


🧪 実例:Next.js でよくある useRef の便利活用

(1) ボタン連打防止

const isSendingRef = useRef(false);

const handleSend = async () => {
  if (isSendingRef.current) return;  

  isSendingRef.current = true;
  await sendMessage();
  isSendingRef.current = false;
};

再レンダーが不要なフラグはこれで十分。


(2) 前回レンダー時の値を保持

const prevValueRef = useRef<string>();

useEffect(() => {
  if (prevValueRef.current !== undefined) {
    console.log("前回値:", prevValueRef.current);
  }
  prevValueRef.current = value;
}, [value]);

(3) video / canvas の DOM 操作

const videoRef = useRef<HTMLVideoElement>(null);

useEffect(() => {
  if (videoRef.current) {
    videoRef.current.play();
  }
}, []);

📝 まとめ

要点 結論
UI を更新したい useState
UI に出ない内部変数 useRef
useRef の方が速い? UI に関係ない処理では YES
DOM にアクセス useRef
再レンダーを抑えたい useRef

React/Next.js では、
「何が UI と関係していて、何が内部状態か?」
を見極めることで設計が大きく変わります。


📚 関連タグ

.htaccessは階層で引き継がれる?Apacheの挙動を徹底解説

MBTI診断

SEO対策に必須!検索上位を狙うsitemap.xmlの完全ガイド

Google Search Consoleの「代替ページ(適切なcanonicalタグあり)」とは?原因と解決法を徹底解説!

Microsoft純正の新しいコンソールエディタ「edit」が復活!| edit.exe インストール方法

Googleサイト確認のTXTレコードをnslookupで確認する方法【SEO対策】

Googleサーチコンソールに反映されるための最低限のSEO構造とは

PHPで複数ファイルを順番に削除する方法

MBTI診断 | あなたの性格タイプを分析

PDFファイル結合|パスワード設定ツール

【Anker Soundcore Liberty 4】イヤーピース紛失!代替品はAmazonで購入

JavaScriptでタイムゾーン変換!UTCとJST(日本時間)の変換方法

pnpmとは?npmとの違いとインストール方法

git switchの使い方とgit checkoutとの違い

HTMLとJavaScriptモジュールでクラスを定義し、ボタンから呼び出す方法

JavaScriptでTensorFlow.jsを動的に読み込む方法|HTMLに直接書かずに機械学習を実行する

ChatGPT風リンクバッジをCSSで作成する

ffmpegでMOVファイルを逆再生する方法【音声付き対応】

Windows 11でタスクマネージャー以外からアプリを終了させる方法【PowerShell・コマンドプロンプト】

macOSでドメイン名から情報を取得する方法【初心者向け】

JavaScriptでPCの空き容量やメモリ量を取得できる?Chromeの制限と代替手法

PowerShellでNode.jsの最新バージョン一覧を確認する方法【Volta/Windows対応】

Next.jsでbasePathを/homepage2にしてS3へ静的デプロイする完全手順

NextAuthなし・APIルートなしで実装:Next.js + AWS Amplify だけでメール/パスワード認証を完結する方法

「Next.js pnpm build (ビルド)後の出力ファイルが見当たらない」トラブルシュート&静的デプロイ

AWS Amplify CLIでS3やZIPから手動デプロイ【実行コマンド付き】

Next.jsで複数サイズのPNGファビコンを指定する方法【layout.tsx対応】

Next.jsでのtypeとinterfaceの違いと使い分け方

Next.js useState と useRef の違いは?最適な使い分け

GraphQL接続の落とし穴:Amplify Hosting(amplifyapp.com) vs S3+Next.js(静的書き出し)比較

Homebrewの「update」と「upgrade」の違い+バージョン確認方法|Macのパッケージ管理

.DS_StoreをGitでアップしない方法|macユーザー向け