【React】setState は React に値を伝えるためのセッターであって代入の純粋な代わりというわけではないという話

  • 2020年11月11日
  • 2020年11月11日
  • React

 React は”ユーザインターフェース構築のための JavaScript ライブラリ”を自称しています。実際 React を使うと素の JavaScript に比べてユーザインタフェースを簡単に多くに正確に作れ、変更もしやすいです。
 そんな React には state という仕組みがあります。
state とライフサイクル – React
 state は”コンポーネント”の状態を表現する仕組みです。もっといえば画面の状態を表現します。具体的な挙動では React のコンポーネントは自身の持つ state が変わった時に画面を再構築(再レンダリング)する、という挙動があります。この state とは現画面の状態という設計が setState を代入の代わりとして考えた時、罠になります。具体的には次です。

    this.state1Increment = () => {
      this.setState({ state1: this.state.state1 + 1 });
      // ↓の記述では↑の setState で渡した state1 でなく state1Increment 実行開始時の state1 が state1Copy にセットされます。
      this.setState({ state1Copy: this.state.state1 });
    };

クリックしてソースコード全体を展開
import React from "react";
import "./styles.css";

class SomeClassComponent extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      state1: 0,
      state1Copy: 0
    };
    this.state1Increment = () => {
      this.setState({ state1: this.state.state1 + 1 });
      this.setState({ state1Copy: this.state.state1 });
    };
  }

  render() {
    return (
      <div className="col">
        <div>state1: {this.state.state1}</div>
        <div>state1copy: {this.state.state1Copy}</div>
        <button onClick={this.state1Increment}>state1++</button>
      </div>
    );
  }
}

function SomeFunctionComponent() {
  const [state1, setStat1] = React.useState(0);
  const [state1Copy, setState1Copy] = React.useState(0);
  const state1Increment = () => {
    setStat1(state1 + 1);
    setState1Copy(state1);
  };
  return (
    <div className="col">
      <div>state1: {state1}</div>
      <div>state1copy: {state1Copy}</div>
      <button onClick={state1Increment}>state1++</button>
    </div>
  );
}
export default function App() {
  return (
    <div className="App">
      <h2>クラスコンポーネント</h2>
      <SomeClassComponent />
      <h2>関数コンポーネント</h2>
      <SomeFunctionComponent />
    </div>
  );
}

 state1 に値を setState でセットする、とした直後に state1Copy に state1 の値をセットする、というコードです。一見 state1Copy に直前に setState でセットするとした値が代入されると思うかもしれませんが、されません。setState でセットした結果をその setState 実行時から次のレンダリングまでに参照しようとすると一つ前の結果が返ってきます。関数コンポーネントの場合、useState で渡される現状態はプリミティブな値として渡されるので「それはそうだろう」という納得の結果ですがクラスコンポーネントでは裏側で変更可能なオブジェクトのプロパティ(extends 元やインスタンスを参照する React のエンジン部とかでそれなりに好き勝手出来る場所)で state を見るため想定と異なる動作と思う時があります。
 ローカル変数を用意する、setState には既に定まった値を入れる、など色々な記述でこの挙動に対応できますが一番は React の思想に付き合うことだと思います。state に関しての話は公式ドキュメントの次が詳しいです。
コンポーネントの state – React

>株式会社シーポイントラボ

株式会社シーポイントラボ

TEL:053-543-9889
営業時間:9:00~18:00(月〜金)
住所:〒432-8003
   静岡県浜松市中央区和地山3-1-7
   浜松イノベーションキューブ 315
※ご来社の際はインターホンで「316」をお呼びください

CTR IMG