3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

【React】state・useStateとは? stateが更新されるタイミングとは?

Posted at

stateとは

  • ユーザーの操作や時間経過などにより変化する値。コンポーネントが持つ可変のデータ。

  • 別のコンポーネントから直接参照・更新することはできない。
     (別のコンポーネントで扱うには、propsやcontextを使う。)

  • stateの状態を管理するにはuseState関数を使う。

useStateの使い方

useStateを利用するためには、useStateをimportする。

import { useState } from 'react';

useStateの宣言

//構文
const [変数名, 関数名] = useState(変数の初期値);

//例
const [count, setCount] = useState(0);
	//setCountメソッドを使ってcountの値を変更することができる

この書き方は、JavaScriptの分割代入の構文。

useStateの宣言をすると、useStateからは2つの要素を持つ配列が返される。

1つ目はstateの現在値、2つ目はstateを更新するための関数。

上の例ではcountとsetCountという名前の2つの変数を作り、useStateから返される値のうち1つ目をcountに、2つ目をsetCountに代入する、という意味になる。

参考:ステートフックの利用法 - React

使ってみる

ローカルでReactの実行環境は作成済みとする。

参考:React.jsを始めよう:動かしながら仕組みを知ろう

src/App.js
//useStateを使うためのimport
import React, { useState } from "react"

function App() {

	//stateの初期値をsountに、stateを更新するための関数をsetCountに代入
  const [count, setCount] = useState(0)

	//setCountを使ってcountを更新する関数を定義
  const increment = () => setCount(count + 1)
  const decrement = () => setCount(count - 1)

  return (
    <div>
      <h3>りんごの在庫:{count}</h3>
      <button onClick={increment}>1つ購入</button>
      <button onClick={decrement}>1つ食べる</button>
    </div>
  )
}

export default App

機能追加してみる

りんごの在庫が0個になると、「1つ食べる」ボタンは押せなくなり、エラーメッセージが表示されるようにしてみる。

src/App.js

import React, { useState } from "react"

function App() {

  const [count, setCount] = useState(0)

	//countが0以下のときtrue、1以上であればfalseになる、disabledを定義
  const disabled = count<=0

  const increment = () =>setCount(count + 1)
  const decrement = () =>setCount(count - 1)

  return (
    <div style={{ margin: "50px" }}>
      <h3>りんごの在庫:{count}</h3>
      <button onClick={increment}>1つ購入</button>
			{//disabledがtrueのとき、HTMLのdisable属性を有効にする}
      <button disabled={disabled} onClick={decrement}>1つ食べる</button>

      {count <= 0 &&
        <h4 style={{ color: "red" }}>
          りんごを食べ切ったよ!!
        </h4>
      }
    </div>
  );
}

export default App

state更新のタイミング

ただしuseStateを使って値を更新しても、即時にstateの値が変わるわけでは無い。

動きを知るため、先ほどのApp.jsにアラートとコンソール への出力を書き足してみる。

src/App.js

import React, { useState } from "react";

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

  const [count, setCount] = useState(0);
  const disabled = count <= 0;

  const increment = () => {
    setCount(count + 1);
    alert(`りんごが${count}個になったよ!`);       //追記
  };
  const decrement = () => setCount(count - 1);

  console.log(`りんごは今${count}個`);            //追記

  return (
    <div style={{ margin: "50px" }}>
      <h3>りんごの在庫:{count}</h3>
      <button onClick={increment}>1つ購入</button>
      <button disabled={disabled} onClick={decrement}>
        1つ食べる
      </button>

      {count <= 0 && <h4 style={{ color: "red" }}>りんごを食べ切ったよ!!</h4>}
    </div>
  );
};

export default App;

するとアラート時点ではstateの値が更新されておらず、コンソール に表示されるときにはstateの値が更新されている。

更新した後の値を即時に使いたい場合は、useStateで扱うstateをそのまま使うのではなく、更新した値を別の変数として定義する。

const increment = () => {
    const newCount = count + 1;
    setCount(newCount);
    alert(`りんごがcount:${count}個、newCount:${newCount}になったよ!`);
  };

以下のように関数を切り分けたとすると…

const increment = () => {
    const newCount = count + 1;
    setCount(newCount);
    alertCount(newCount);
  };

const alertCount = (newCount) => {
  alert(`りんごがcount:${count}個、newCount:${newCount}個になったよ!`);
  };

やはりstateはalertCountを呼び出す時点では更新されていないことがわかる。

さいごに

useStateの特徴

  • ページをリロードするとstateはリセットされる(初期値になる)
  • stateが更新されるごとに、コンポーネントは再レンダリングされる

レンダリングとは

stateやpropsの変更差分を反映したDOMを再構築すること。

レンダリングが起きると、コンポーネントの頭から処理が順に行われる。

参考記事

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

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?