2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【React】useState の遅延初期化(lazy initialization)とは

Posted at

はじめに

こんにちは。アメリカ在住で独学エンジニアを目指している Taira です。

useState の初期値を設定するとき、次のように書いたことはありませんか?

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

このように書くと、expensiveComputation() がレンダーのたびに実行されることがあります。
パフォーマンスの低下や、意図しない副作用の原因になることもあります。

この記事では、ReactのuseStateにおける「遅延初期化(lazy initialization)」について、
「なぜ() =>をつけると初回だけ実行されるのか?」を解説します。


🧬 useStateの仕様を理解する

useState は、次のようなシグネチャを持っています。

const [state, setState] = useState<T>(initialState: T | (() => T));

つまり、初期値には「値」か「関数」を渡せる仕様になっています。

React の内部では、このようなイメージで処理が行われます👇

const useState = (initialState) => {
  if (isFirstRender) {
    if (typeof initialState === "function") {
      // 関数が渡された場合 → 初回マウント時に一度だけ実行して値を決定
      state = initialState();
    } else {
      // 値が渡された場合 → そのまま初期値として使用
      state = initialState;
    }
  }
  return [state, setState];
};

この仕様により、

  • 関数を渡すと → Reactが初回マウント時に一度だけ呼び出す
  • 値を渡すと → そのまま使う(呼び出しはしない)

という動作の違いが生まれます。


💡 遅延初期化の書き方

// ❌ NG:毎回レンダーのたびに関数が呼ばれる
const [count, setCount] = useState(expensiveComputation());

// ✅ OK:Reactが初回のみ関数を呼ぶ
const [count, setCount] = useState(() => expensiveComputation());

違いは、関数をその場で実行しているか、Reactに任せているかです。


⚙️ 違いをコードで確認

const expensiveComputation = () => {
  console.log("heavy function called");
  return 42;
};

const App = () => {
  console.log("render");

  const [a] = useState(expensiveComputation());
  const [b] = useState(() => expensiveComputation());

  return (
    <div>
      <p>a: {a}</p>
      <p>b: {b}</p>
    </div>
  );
};

🗒 コンソール出力(クリックで再レンダー)

render
heavy function called  ← a(毎回実行)
heavy function called  ← b(初回だけ)
  • useState(expensiveComputation())
    → JavaScriptがuseStateを呼ぶ前に関数を評価している
  • useState(() => expensiveComputation())
    → Reactが初回マウント時のみ評価している

🤠 useMemoとの違い

「初回だけ実行」と聞くと、useMemoを思い浮かべる人も多いと思います。
しかし、両者の目的は異なります。

フック 実行タイミング 目的
useState(() => …) 初回レンダー時のみ 初期値を計算してstateに保存
useMemo(() => …, []) 初回レンダー時のみ 計算結果をキャッシュ

どちらも初回だけ実行されますが、
useState は「状態を保持」し、useMemoは「値をキャッシュ」するだけです。


🚀 まとめ

ポイント 内容
仕様 useStateは、引数が関数なら初回のみ実行、値ならそのまま評価
目的 初期値の計算を遅延させて無駄な再評価を防ぐ
書き方 useState(() => 初期化関数)
効果 パフォーマンス改善・意図しない副作用防止
補足 useMemoは値キャッシュ、useStateは状態管理

🎯 さいごに

() =>をつけると初回だけ実行される」と聞くと魔法のように思えますが、
実際は React の useState

「関数を渡されたら初回マウント時にだけ評価する」
という仕様になっているだけです。

つまり本質はこうです👇

useState(expensiveComputation()) は「JavaScriptが呼ぶ」
useState(() => expensiveComputation()) は「Reactが呼ぶ」

参考記事

2
0
1

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

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?