1
1

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を理解する!

Last updated at Posted at 2024-05-12

stateとは

React コンポーネントで管理される状態です。

state が更新されると、コンポーネントは再レンダリングされます。
状態を持つ必要があるコンポーネントでstateを利用します。

  • カウンター
  • タイマー など

useState

stateを利用する場合、 useStateメソッドを利用します。
useStateの戻り値として、状態と状態更新するための更新関数が返されます。

詳しくみていきましょう。

const [state, setState] = useState(initialState);
  • initialStatestate の初期値を指定
  • useState は二つの要素を持つタプルを返す。
    • state => state の値
    • setState => state を更新するための関数

この setState 関数を使って、新しい state 値を設定することができます。
更新が発生すると、コンポーネントはその state をもって再レンダリングされます。

型指定

state変数の型は初期値を元に推論されます。
そのため、stateの初期値がnullの場合などは、明示的に型を指定します。

const [state, setState] = useState<number | null>(null);

Reactの単方向データフロー / Stateのリフトアップ

Reactは 単方向データフロー を採用しています。
データ(state, props)が親コンポーネントから子コンポーネントへ一方的に流れるという設計原則です。

そのため、複数コンポーネントで共通して管理する必要があるstateは 親コンポーネントで管理され、 更新関数が子コンポーネントに渡されることが多いです。
これを stateのリフトアップ と言います。

image.png

画像引用
https://www.techpit.jp/courses/22/curriculums/23/sections/197/parts/696

サンプルコード

import React, { useState } from 'react';
import ChildComponent from './ChildComponent';

const ParentComponent = () => {
    const [count, setCount] = useState(0);

    const incrementCount = () => {
        setCount(count + 1);
    };

    return (
        <div>
            <h1>Count: {count}</h1>
            <ChildComponent onIncrement={incrementCount} />
        </div>
    );
};

export default ParentComponent;
import React from 'react';

const ChildComponent = ({ onIncrement }) => {
    return (
        <button onClick={onIncrement}>Increment</button>
    );
};

export default ChildComponent;

setStateにコールバックを渡す

stateの更新は非同期に行われます。
そのため、以下のようなコードは連続してクリックされた場合、stateの値が想定された値にならない可能性があります。

const handleClick = () => {
    setCount(count + 1);
    setCount(count + 1);
    setCount(count + 1);
};

対策として、更新用のコールバック関数を渡すことができます。
この関数は実行時の最新のstate値を引数に取るため、非同期で処理された場合も問題なくカウントアップが実行されます。

const handleClick = () => {
    setCount(prevCount => prevCount + 1);
    setCount(prevCount => prevCount + 1);
    setCount(prevCount => prevCount + 1);
};

Hooksの呼び出しは関数コンポーネントのTOPで行う必要がある

React では、Hooks の呼び出し順がコンポーネントの各レンダリング間で一貫性を保つため、Hooks を関数コンポーネントのトップレベルでのみ呼び出す必要があります。

import { useState } from 'react';

const SampleComponent = () => {
  if(true){ 
    // NG: `React Hook "useState" is called conditionally. React Hooks must be called in the exact same order in every component render.`
    const [count, setCount] = useState(0);
  }

  return (
    <div>
      <h1>Count: {count}</h1>
      <button onClick={() => setCount((c) => c + 1)}>click</button>
    </div>
  );
};

export default SampleComponent;


オブジェクト / 配列 のstate管理

setState を使用して state を更新する際は、特にオブジェクトや配列の場合、新しい参照を作成する必要があります。

参照が変更されていない場合、コンポーネントは再レンダリングされません
以下のように、既存の配列、オブジェクトを複製する必要があります。

const newArray = [...array];

const newState = {...state, updatedProperty: newValue};

まとめ

以上です。
本記事では表面的なところしか触れていませんが、メカニズムの理解がすごく楽しめました。

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

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?