👌

useState 注意点

2023/06/13に公開

reactで簡単なカウントアプリを作成していて想定どおり動かなかったところがありました。
原因がわかってスッキリしたので忘れないように残しておきます。

+2されるカウントアップを作ったが+1しかされない

  • +1されるカウントアップ
Count.tsx
import React, { useState } from "react";

export const CountUp = () => {
  const [count, setCount] = useState(0);
  const countUp = () => {
    setCount(count + 1);
  }
  return (
    <div className="text-center">
      <h1 className="text-5xl pt-10">Count: {count}</h1>
      <button 
        onClick={countUp} 
        className="m-10 p-5 border-4 border-black rounded-xl bg-rose-500 text-gray-200 text-2xl">
        カウントアップ
      </button>
    </div>
  );
};

これは問題なく+1される

  • +2されるカウントアップ
Count.tsx
import React, { useState } from "react";

export const CountUp = () => {
  const [count, setCount] = useState(0);
  const CountUp = () => {
    setCount(count + 1);
    setCount(count + 1);
  }
  return (
    <div className="text-center">
      <h1 className="text-5xl pt-10">Count: {count}</h1>
      <button 
        onClick={CountUp} 
        className="m-10 p-5 border-4 border-black rounded-xl bg-rose-500 text-gray-200 text-2xl">
        カウントアップ
      </button>
    </div>
  );
};

setCountを2回呼び出しているにもかかわらず+1しかされませんでした。

なぜ?

stateの更新は即座に行われるわけではなく、setCountが非同期処理で呼び出されるため。
2回目のsetCountの時点ではまだstateが更新していない。
解決するには前のstateの値を参照する必要があるのでsetCountの中身をコールバック関数で記述してあげるとうまく動きました。

  • 修正後のCount.tsx
Count.tsx
import React, { useState } from "react";

export const CountUp = () => {
  const [count, setCount] = useState(0);
  const countUp = () => {
    setCount((count) => count + 2);
  }
  return (
    <div className="text-center">
      <h1 className="text-5xl pt-10">Count: {count}</h1>
      <button 
        onClick={countUp} 
        className="m-10 p-5 border-4 border-black rounded-xl bg-rose-500 text-gray-200 text-2xl">
        カウントアップ
      </button>
    </div>
  );
};

Discussion