LoginSignup
1
1

[React] Stateについて理解する

Posted at

stateとは

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

state が更新されると、コンポーネントは再レンダリングされます。


useState

関数コンポーネントで state を扱う場合、 useStateを利用します。

const [state, setState] = useState(initialState);
  • initialState は state の初期値を指定
  • 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のリフトアップ と言います。

サンプルコード

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