🐮

React の useState と useRef、何が違うの?再レンダーの仕組みから理解する

に公開

導入

React を書いていると、useStateuseRef の使い分けで迷うことがあります。
特に「値を保持したいけど、再レンダーはさせたくない」という場面で、
どっちを使えばいいのかと思ったこと、ありませんか?

この記事では、「再レンダー」「再マウント」の違いも踏まえて
useStateuseRef の本質を整理します。


再レンダーと再マウントの違い

用語 意味 何が起きる?
再レンダー (re-render) 同じコンポーネントのインスタンスで再描画 state や ref は保持される
再マウント (re-mount) いったん破棄 → 新しく作り直し state や ref がリセットされる

key が変わると再マウント
state の変更などが起きると再レンダーです。


再レンダー・再マウント時にどうなるか

フック/値 再レンダー時 再マウント時
useState 値は保持 初期化される
useRef 値は保持 初期化される
useMemo / useCallback 依存が変わらなければ保持 再計算される
useEffect 依存が変われば再実行 初回から再実行(アンマウント → マウント)
DOM ノード 差分更新 一度破棄して再生成

つまり「再レンダー」は“同じインスタンス内で再評価”、
「再マウント」は“まったく新しいインスタンスに差し替え”です。


useStateuseRef の違い

項目 useState useRef
値を変えると再レンダー? する しない
UI に影響する値に向いてる? 向いてる 向いてない
一時的な値を覚えておくのに向いてる? 不向き 向いてる
更新方法 setValue(newVal) ref.current = newVal
再レンダー間で値を保持する? する する

例:カウンター(useState)

function Counter() {
  const [count, setCount] = useState(0);
  return (
    <button onClick={() => setCount(count + 1)}>
      count: {count}
    </button>
  );
}

クリック → setCount再レンダー発生 → UI 更新。


例:useRef で再レンダーしない値を保持

function Timer() {
  const startTime = useRef(Date.now());

  useEffect(() => {
    const id = setTimeout(() => {
      console.log("経過時間(ms):", Date.now() - startTime.current);
    }, 5000);
    return () => clearTimeout(id);
  }, []);

  return <p>5秒後にコンソールに出ます</p>;
}

useRef の値は変わっても再レンダーしない。
UI に出さない“裏の状態”を持つのに最適。


💬 使い分け

状況 使うべきフック
UI に表示される値 useState
タイマーID・前回の値・スクロール位置など useRef
値を変えてもUIを変えたくない useRef
値を変えたらUIも更新したい useState

まとめ

React の「状態管理フック」は、
「UIに影響するかどうか」と「再レンダーを起こしたいかどうか」で使い分ける。

UIのための状態 → useState
ロジックのためのメモ → useRef

Discussion