0
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: 関数型アップデートと普通の更新の違い

Posted at

↓サンプルコード

import { useState } from "react";

export default function Counter() {
  const [foo, setFoo] = useState(1);

  // 書き方①: 関数型アップデート
  const handleClickFunc = () => {
    setFoo((prevFoo) => prevFoo + 1);
  };

  // 書き方②: 現在値を直接使用
  const handleClickDirect = () => {
    setFoo(foo + 1);
  };

  return (
    <div>
      <h1>{foo}</h1>
      <button onClick={handleClickFunc}>
        関数型アップデートで +1
      </button>
      <button onClick={handleClickDirect}>
        現在値で +1
      </button>
    </div>
  );
}

React の useState で状態を更新する際、以下の二つの書き方は似ているようで 挙動に違いがある。

// 書き方①
const handleClick = (e) => {
  setFoo((foo) => foo + 1);
};

// 書き方②
const handleClick = (e) => {
  setFoo(foo + 1);
};

書き方①: 関数型アップデート

  • setFoo に関数 (foo) => foo + 1 を渡している
  • 引数 foo には 常に最新の状態が渡される
  • 複数回の更新や非同期処理が絡んでも、状態の競合が起きにくい
  • 推奨される書き方である
setFoo((foo) => foo + 1);
setFoo((foo) => foo + 1); // 2回呼んでも foo は正しく +2 される

現在の変数を直接使用

  • 現在の状態 foo を使って更新している
  • ただし、この foo は レンダリング時に関数内で評価された値
  • 複数回の連続更新や非同期処理で、最新状態が反映されない可能性がある
  • 単純なクリックなど、1 回ずつの更新であれば問題はないが、安全ではない
setFoo(foo + 1);
setFoo(foo + 1); // 連続で呼ぶと +1 しか反映されないことがある

まとめ

  • 複数回の更新や非同期処理に対応するには、関数型アップデート (prev) => prev + 1 を使うべきである
  • 単純な 1 回クリックの処理であれば foo + 1 でも動作するが、安全性が低い
  • React では 状態の更新は常に「最新の状態」を基に行う ことが推奨される
0
0
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
0
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?