Reactでコンストラクタなしで状態を初期化する 質問する

Reactでコンストラクタなしで状態を初期化する 質問する
import React, { Component } from 'react';

class Counter extends Component {
  state = { value: 0 };

  increment = () => {
    this.setState(prevState => ({
      value: prevState.value + 1
    }));
  };

  decrement = () => {
    this.setState(prevState => ({
      value: prevState.value - 1
    }));
  };

  render() {
    return (
      <div>
        {this.state.value}
        <button onClick={this.increment}>+</button>
        <button onClick={this.decrement}>-</button>
      </div>
    )
  }
}

通常、私が見たのは、es6 クラスを使用している場合、コンストラクター関数内で this.state を実行する人々です。そうでない場合は、getinitialstate 関数を使用して状態を設定している可能性があります。ただし、上記のコード (はい、動作するコードです) では、どちらも使用されていません。2 つの質問があります。ここでの状態とは何ですか? これはローカル変数ですか? そうである場合、なぜありませんかconst? prevState はどこから来るのですか? setState で矢印関数が使用されるのはなぜですか? 簡単に実行できないのですかthis.setState({value:'something'})?

ベストアンサー1

質問が2つあります。stateここには何があるのでしょうか?

インスタンスプロパティ、this.state = {value: 0};コンストラクタでの設定のようなもの。パブリッククラスフィールドの提案increment現在、ステージ 2 です。(と も同様ですdecrement。これらはインスタンス フィールドであり、その値は矢印関数であるため、 の上に閉じますthis。)

それはローカル変数ですか?

いいえ。

prevState はどこから来るのでしょうか? setState で矢印関数が使用されるのはなぜですか? this.setState({value:'something'}) を実行するのは簡単ではないのでしょうか?

からドキュメント:

React はsetState()パフォーマンスのために、複数の呼び出しを 1 つの更新にまとめる場合があります。

this.propsおよび は非同期的に更新される可能性があるためthis.state、次の状態を計算する際にそれらの値に依存しないでください。

たとえば、次のコードではカウンターの更新に失敗する可能性があります。

// Wrong
this.setState({
  counter: this.state.counter + this.props.increment,
});

これを修正するには、オブジェクトではなく関数を受け入れる の 2 番目の形式を使用しますsetState()。その関数は、最初の引数として以前の状態を受け取り、2 番目の引数として更新が適用された時点のプロパティを受け取ります。

// Correct
this.setState((prevState, props) => ({
  counter: prevState.counter + props.increment
}));

...これはまさに引用したコードが行っていることです。これは間違いです:

// Wrong
increment = () => {
  this.setState({
    value: this.state.value + 1
  });
};

... は の状態に依存しているためですがthis.state、上記ではそうしないように指示されています。そのため、引用されたコードは代わりにこれを行います。

increment = () => {
  this.setState(prevState => ({
    value: prevState.value + 1
  }));
};

Reactがわかりにくい方法でバッチ呼び出しを行う可能性があることと、のコールバックバージョンを使用する必要がある理由の証拠を以下に示します。setStateここでは、incrementおよびdecrementが呼び出されます。2回1回のクリックではなく、1回のクリック(ボタンごとに1回、ボタンを含むスパンごとに1回)です。+ 一度は 2 回呼び出されるため、カウンタを 2 に増やす必要がありますincrement。しかし、 の関数コールバック バージョンを使用していないためsetState、そうはなりません。 の呼び出しの 1 つは、increment古い値を使用しているため、何も実行されませんthis.state.value

class Counter extends React.Component {
  state = { value: 0 };

  increment = () => {
    /*
    this.setState(prevState => ({
      value: prevState.value + 1
    }));
    */
    console.log("increment called, this.state.value = " + this.state.value);
    this.setState({
      value: this.state.value + 1
    });
  };
  
  fooup = () => {
    this.increment();
  };

  decrement = () => {
    /*
    this.setState(prevState => ({
      value: prevState.value - 1
    }));
    */
    console.log("decrement called, this.state.value = " + this.state.value);
    this.setState({
      value: this.state.value - 1
    });
  };
  
  foodown = () => {
    this.decrement();
  };

  render() {
    return (
      <div>
        {this.state.value}
        <span onClick={this.fooup}>
          <button onClick={this.increment}>+</button>
        </span>
        <span onClick={this.foodown}>
          <button onClick={this.decrement}>-</button>
        </span>
      </div>
    )
  }
}

ReactDOM.render(
  <Counter />,
  document.getElementById("react")
);
<div id="react"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>

関数コールバックを使用すると、正しく動作します ( incrementno-ops になる呼び出しはありません)。

class Counter extends React.Component {
  state = { value: 0 };

  increment = () => {
    this.setState(prevState => {
      console.log("Incrementing, prevState.value = " + prevState.value);
      return {
        value: prevState.value + 1
      };
    });
  };
  
  fooup = () => {
    this.increment();
  };

  decrement = () => {
    this.setState(prevState => {
      console.log("Decrementing, prevState.value = " + prevState.value);
      return {
        value: prevState.value - 1
      };
    });
  };
  
  foodown = () => {
    this.decrement();
  };

  render() {
    return (
      <div>
        {this.state.value}
        <span onClick={this.fooup}>
          <button onClick={this.increment}>+</button>
        </span>
        <span onClick={this.foodown}>
          <button onClick={this.decrement}>-</button>
        </span>
      </div>
    )
  }
}

ReactDOM.render(
  <Counter />,
  document.getElementById("react")
);
<div id="react"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>

この場合、もちろん、renderメソッドを見て「incrementクリック中に2回呼び出されるので、のコールバックバージョンを使用する方が良いsetState」と言うことができます。しかし、次の状態を決定するときに使用しても安全であると想定するのではなくthis.state、ベストプラクティスは次のとおりです。ないそれを前提としています。複雑なコンポーネントでは、ミューテーター メソッドの作成者が考えていなかった方法でミューテーター メソッドを使用することは簡単です。そのため、React の作成者は次のように述べています。

this.propsおよびは非同期的に更新される可能性があるためthis.state次の状態を計算するためにそれらの値に頼るべきではない

おすすめ記事