1
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] Stateの動作

1
Posted at

stateについて。
stateは各コンポーネントが持っている状態を管理する。
今エラーがあるのか、モーダルが開いているのか、
ユーザーの入力内容や、APIから取ってきたデータの内容など。
これらを状態として管理する。

import { useState } from 'react';

import { ColorfulMessage } from './components/ColorfulMessage';

export const App = () => {
  const [num, setNum] = useState(0);

  const onClickCountUp = () => {
    setNum(111);
  };
  return (
    <>
      <h1 style={{ color: 'red' }}>こんにちは</h1>
      <ColorfulMessage color="blue">元気ですか??</ColorfulMessage>
      <ColorfulMessage color="green"> 元気です!</ColorfulMessage>

      <button onClick={onClickCountUp}>カウントアップ</button>
      <p>{num}</p>
    </>
  );
};
const [num, setNum] = useState(0);

と書くと、numには初期値が 0が入る。
setNumは更新関数で、
ボタンをクリックすると、以下の関数で、numに111が入る。

  const onClickCountUp = () => {
    setNum(111);
  };

setNumの引数を、num + 1 にすると、1ずつカウントアップする。

  const onClickCountUp = () => {
    setNum(num + 1);
  };

setNum(num + 1); を、2回書いても、
1ずつカウントアップする。

  const onClickCountUp = () => {
    setNum(num + 1);
    setNum(num + 1);
  };

setNumには、関数を引数とすることもできて、
setNum((prev) => prev + 1);
こう書くと、
引数のprevは今のnumの値を意味する。

  const onClickCountUp = () => {
    setNum((prev) => prev + 1);
  };

これも1つずつカウントアップする。

setNum((prev) => prev + 1);を2回連続で書くと、

  const onClickCountUp = () => {
    setNum((prev) => prev + 1);
    setNum((prev) => prev + 1);
  };

これは、2ずつカウントアップされる。

なんでそうなるのかAIに聞いた。

参考にしてる、udemyの解説とかブログ記事とか読んでもよく分からなかったので、

以下のように、

setNum(num + 1); 2回連続で呼んでも、num は +2 されずに +1になるのはなぜ?

とジェミニに聞いた。

  const onClickCountUp = () => {
    setNum(num + 1);
    setNum(num + 1);
  };

以下ジェミニの声

Reactのステート(状態)は、そのレンダリング時の値のスナップショットとして保持されるためです。

num が 0 の状態でボタンをクリックして onClickCountUp が実行されたとき、関数内の num は常に 0 として評価されます。そのため、内部の処理は以下のようになります。

1回目の setNum(num + 1) は setNum(0 + 1) として評価され、ステートを 1 に更新する予約をします。

2回目の setNum(num + 1) も まだ num は 0 のまま なので setNum(0 + 1) として評価され、ステートを 1 に更新する予約で上書きされます。

結果として、何度 setNum(num + 1) を連続で呼んでも、次のレンダリングで num は 1 にしかなりません。

解決策

直前のステートの値を確実に見る必要がある場合は、コールバック関数(Updater function)を渡す書き方に変更します。

const onClickCountUp = () => {
  setNum((prevNum) => prevNum + 1); // 現在の最新のステート(prevNum)を受け取って +1 する
  setNum((prevNum) => prevNum + 1); // 直前の処理結果が反映された状態で +1 される
};

このように書くことで、1回目で +1 された結果を2回目が受け取ってさらに +1 するため、期待通りに +2 されるようになります。

------

理解できたような気がした。

1
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
1
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?