技術っぽいことを書いてみるブログ

PythonとかVue.jsとか技術的なことについて書いていきます。

Reactについて学ぶ(コンポーネントにstateを持たす編)

はじめに

Reactのコンポーネントにstateを持たせる方法についてまとめておきます。

Reactで、何かしらの操作に応じて、画面上の表示を変更するためには、
コンポーネント自体にstate(状態)を持たせる必要があります。

Reactでは、stateではない変数が変化しても、画面上の表示は変化しません。
参考までに・・・、以下のようなプログラムでは、画面上の表示は変化しません。
なお、コンソール上では、値は変わっています。

import { FC } from 'react';

const Test: FC = () => {
  let count = 0;

  const clickHandler = () => {
    console.log('clickHandler', count);
    count++;
  };
  return (
    <div>
      <span>{count}</span>
      <button onClick={() => clickHandler()}>click</button>
    </div>
  );
};

export default Test;

stateの使い方

import { FC, useState } from 'react'; 

const AboutState: FC = () => {
  const [count, setCount] = useState(0);  // ①

  const clickHandler = () => {
    setCount((now) => now + 1);
  };

  return (
    <div>
      <span>{count}</span>
      <button onClick={clickHandler}>Click!</button>
    </div>
  );
};

export default AboutState;
  • 解説
    • stateは、useStateで作成します。
    • useStateの引数は、初期値となります。
      • 引数で渡した値で型推論されるので、初期値をセットする場合の型指定は不要。
    • 初期値を指定しない場合は、useState<number>(); のように型を指定するようにしましょう。
      • この場合、初期値がないので、number | undefinedのユニオン型になります。
    • useStateの戻り値は、値を保持する変数と、値を変更するセッターがタプルとして返却されます。
      • 一般的には分割代入して受け取ります。
      • 変数がhogeなら、 セッターはsetHogeが慣例の模様。
    • セッターの引数は、変更したい値でstateを変更する場合と、更新関数で値を変更する場合とがあります。
      • 値を引数にして、stateを変更する場合:useCount(5)
      • 更新関数を引数にして、stateを変更する場合:'useCount((n) => n + 1 );`
        • この場合、更新関数の引数は現在の値となります。

stateのセッターの注意点

clickHandlerの部分で、セッターで更新関数ではなく、値の代入として、3回現在の値+1するようにした。

import { FC, useState } from 'react';

const AboutState: FC = () => {
  const [count, setCount] = useState(0);

  const clickHandler = () => {
    [...Array(3)].forEach(() => setCount(count + 1));  // ★
  };

  return (
    <div>
      <span>{count}</span>
      <button onClick={clickHandler}>Click!</button>
    </div>
  );
};

export default AboutState;
  • 動作はどうなるか?
    • 1回のボタン押下で、3足されず、1しか足されない

更新関数で書き換えてみる…

import { FC, useState } from 'react';

const AboutState: FC = () => {
  const [count, setCount] = useState(0);

  const clickHandler = () => {
    [...Array(3)].forEach(() => setCount((now) => now + 1));  // ★
  };

  return (
    <div>
      <span>{count}</span>
      <button onClick={clickHandler}>Click!</button>
    </div>
  );
};

export default AboutState;
  • 動作はどうなるか?

    • 3回実行した分、3足されている
  • なぜ?

    • Reactでは、値が変更されてレンダリングのためコンポーネント自体が実行される際、
      レンダリングが終わるまでは、stateの値は一定で変わらない。
    • コンポーネント実行中にセッターでstateの値が変更された場合、レンダリングが終わるまではstateの値は変わらず、終わってから次回の値が受け取れるようになる。
    • これを回避するためには、余計なバグを生み出さないためにも、更新関数を渡す方が無難。

最後に・・・

今回は、Reactのstateについて、確認しました。

次回は、useEffect編を予定しています。