web-dev-qa-db-ja.com

setStateは状態をすぐに更新しません

Onclickイベントを実行したときに状態が変化しない理由を尋ねたいと思います。少し前に、コンストラクターでonclick関数をバインドする必要があるが、まだ状態が更新されていないことを検索しました。ここに私のコードがあります:

import React from 'react';

import Grid from 'react-bootstrap/lib/Grid';
import Row from 'react-bootstrap/lib/Row';
import Col from 'react-bootstrap/lib/Col';

import BoardAddModal from 'components/board/BoardAddModal.jsx';

import style from 'styles/boarditem.css';

class BoardAdd extends React.Component {

    constructor(props){
        super(props);

        this.state = {
            boardAddModalShow: false
        }

        this.openAddBoardModal = this.openAddBoardModal.bind(this);
    }
    openAddBoardModal(){
        this.setState({ boardAddModalShow: true });
// After setting a new state it still return a false value
        console.log(this.state.boardAddModalShow);

    }

    render() {

        return (
            <Col lg={3}>
                <a href="javascript:;" className={style.boardItemAdd} onClick={this.openAddBoardModal}>
                    <div className={[style.boardItemContainer,style.boardItemGray].join(' ')}>
                        Create New Board
                    </div>
                </a>



            </Col>
        )
    }
}

export default BoardAdd
67
Sydney Loteria

このコールバックは本当に面倒です。代わりにasync awaitを使用してください:

async openAddBoardModal(){
    await this.setState({ boardAddModalShow: true });
    console.log(this.state.boardAddModalShow);
}
7
Spock

状態が変化するのに時間がかかります。状態が変化する前にconsole.log(this.state.boardAddModalShow)が実行されるため、出力として前の値を取得します。したがって、setState関数へのコールバックでコンソールを作成する必要があります

openAddBoardModal(){
        this.setState({ boardAddModalShow: true }, function () {
             console.log(this.state.boardAddModalShow);
        });

}

setStateは非同期です。つまり、ある行でsetStateを呼び出して、次の行で状態が変化したと想定することはできません。

React docs

setState()はすぐにthis.stateを変更しませんが、保留中の状態遷移を作成します。このメソッドを呼び出した後にthis.stateにアクセスすると、既存の値が返される可能性があります。 setStateの呼び出しの同期操作の保証はなく、パフォーマンス向上のために呼び出しをバッチ処理できます。

setStateを非同期にする理由

これは、setStateが状態を変更し、再レンダリングを引き起こすためです。これはコストのかかる操作になる可能性があり、同期化するとブラウザが応答しなくなる場合があります。

したがって、setState呼び出しは非同期であり、UIエクスペリエンスとパフォーマンスを向上させるためにバッチ処理されます。

116
Shubham Khatri

幸いなことに setStateはコールバックを受け取ります。そして、ここで更新された状態を取得します。この例を考えてみましょう。

this.setState(
    { name: "Mustkeom" },
      () => {                        //callback
        console.log(this.state.name) // Mustkeom
      }
);

そのため、コールバックが発生すると、this.stateは更新された状態になります。コールバックで変更/更新されたデータを取得できます。

21
Asif J

SetSatateは非同期関数なので、このようなコールバックとして状態をコンソールする必要があります。

openAddBoardModal(){
    this.setState({ boardAddModalShow: true }, () => {
        console.log(this.state.boardAddModalShow)
    });
}
11
Adnan shah

setState()は、必ずしもすぐにコンポーネントを更新するとは限りません。更新がバッチ処理されるか、後まで延期される場合があります。これにより、setState()を呼び出した直後にthis.stateを読み取ることが潜在的な落とし穴になります。代わりに、componentDidUpdateまたはsetStateコールバック(setState(updater, callback))を使用します。いずれも、更新プログラムの適用後に起動することが保証されています。前の状態に基づいて状態を設定する必要がある場合は、以下のupdater引数についてお読みください。

setState()は、shouldComponentUpdate()がfalseを返さない限り、常に再レンダリングされます。可変オブジェクトが使用されており、shouldComponentUpdate()で条件付きレンダリングロジックを実装できない場合、新しい状態が前の状態と異なる場合にのみsetState()を呼び出すと、不要な再レンダリングが回避されます。

最初の引数は、署名付きの更新関数です。

(state, props) => stateChange

stateは、変更が適用される時点でのコンポーネントの状態への参照です。直接変異させないでください。代わりに、状態と小道具からの入力に基づいて新しいオブジェクトを構築することにより、変更を表す必要があります。たとえば、props.stepによって状態の値をインクリメントしたいとします。

this.setState((state, props) => {
    return {counter: state.counter + props.step};
});
5
Aman Seth

はい。setStateは非同期関数であるためです。設定状態を記述した直後に状態を設定する最良の方法は、次のようにObject.assignを使用することです。たとえば、プロパティisValidをtrueに設定するには、次のようにします。


Object.assign(this.state、{isValid:true})


この行を書いた直後に更新された状態にアクセスできます。

2
Dipanshu Sharma

状態が更新されているかどうかを追跡する場合、同じことを行う別の方法は

_stateUpdated(){
  console.log(this.state. boardAddModalShow);
}

openAddBoardModal(){
  this.setState(
    {boardAddModalShow: true}, 
    this._stateUpdated.bind(this)
  );
}

これにより、デバッグのために状態を更新しようとするたびに、メソッド「_stateUpdated」を呼び出すことができます。

2
Ravin Gupta

setStateは非同期関数であるため、次のように使用する必要がある場合があります。

this.setState({key:value},()=>{ callYourFunction(this.state.key) });
0
Preetham NT

setState()は非同期です。状態が更新されているかどうかを確認する最善の方法は、componentDidUpdate()の後にconsole.log(this.state.boardAddModalShow)を置かずにthis.setState({ boardAddModalShow: true })を使用することです。

React Docs に従って

SetState()は、コンポーネントを更新するための即時コマンドではなく、リクエストと考えてください。パフォーマンスを向上させるために、Reactはそれを遅らせ、1回のパスでいくつかのコンポーネントを更新します。 Reactは、状態の変更がすぐに適用されることを保証しません

0
stuli

React Docs による

Reactは、状態の変更がすぐに適用されることを保証しません。これにより、setState()を呼び出した直後にthis.stateが潜在的なpitfallになり、existingの性質によりasync値を返す可能性があります。代わりに、setState操作が成功した直後に実行されるcomponentDidUpdateまたはsetStateコールバックを使用します。通常、このようなロジックにはcomponentDidUpdate()を使用することをお勧めします。

例:

import React from "react";
import ReactDOM from "react-dom";

import "./styles.css";

class App extends React.Component {
  constructor() {
    super();
    this.state = {
      counter: 1
    };
  }
  componentDidUpdate() {
    console.log("componentDidUpdate fired");
    console.log("STATE", this.state);
  }

  updateState = () => {
    this.setState(
      (state, props) => {
        return { counter: state.counter + 1 };
      });
  };
  render() {
    return (
      <div className="App">
        <h1>Hello CodeSandbox</h1>
        <h2>Start editing to see some magic happen!</h2>
        <button onClick={this.updateState}>Update State</button>
      </div>
    );
  }
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

0
khizer
 this.setState({
    isMonthFee: !this.state.isMonthFee,
  }, () => {
    console.log(this.state.isMonthFee);
  })