web-dev-qa-db-ja.com

React setStateメソッドを呼び出してもすぐに状態が変化しないのはなぜですか?

私は Formsreactjs のドキュメントのセクションを読んでいて、onChangeの使用法を示すためにこのコードを試してみました( _ jsbin _ )。

var React= require('react');

var ControlledForm= React.createClass({
    getInitialState: function() {
        return {
            value: "initial value"
        };
    },

    handleChange: function(event) {
        console.log(this.state.value);
        this.setState({value: event.target.value});
        console.log(this.state.value);

    },

    render: function() {
        return (
            <input type="text" value={this.state.value} onChange={this.handleChange}/>
        );
    }
});

React.render(
    <ControlledForm/>,
  document.getElementById('mount')
);

ブラウザで<input/>値を更新すると、handleChangeコールバック内の2番目のconsole.logは、最初のconsole.logと同じvalueを出力します。なぜhandleChangeコールバックのスコープ内にthis.setState({value: event.target.value})の結果が表示されないのですか。

254
tarrsalah

Reactの ドキュメンテーション :から

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

状態が変化した後に関数を実行したい場合は、コールバックとして渡します。

this.setState({value: event.target.value}, function () {
    console.log(this.state.value);
});
513
Michael Parker

Reactのドキュメントで述べたように、setStateが同期的に起動されるという保証はないので、あなたのconsole.logは更新前の状態を返すかもしれません。

Michael ParkerはsetState内でコールバックを渡すことに言及しています。状態変更後にロジックを処理するもう1つの方法は、Reactのドキュメントで推奨されている方法であるcomponentDidUpdateライフサイクルメソッドを使用することです。

通常、そのようなロジックには代わりにcomponentDidUpdate()を使用することをお勧めします。

これは連続したsetStateが起動される可能性があり、すべての状態が変化した後に同じ関数を起動したい場合に特に便利です。各setStateにコールバックを追加するのではなく、必要に応じて特定のロジックを内部に置いて、関数をcomponentDidUpdateの内部に配置できます。

// example
componentDidUpdate(prevProps, prevState) {
  if (this.state.value > prevState.value) {
    this.foo();  
  }
}
40
Yo Wakita

あなたはES7 async/awaitを使ってみることができます。例えばあなたの例を使って:

handleChange: async function(event) {
    console.log(this.state.value);
    await this.setState({value: event.target.value});
    console.log(this.state.value);
}
8
black

反応するライフサイクルメソッドに気をつけてください!

私はgetDerivedStateFromPropssetState()ごとに呼ばれることを知るために数時間働きました。

????

5
osrpt

async-await構文は、次のようなものには完璧に機能します。

changeStateFunction = () => {
  // Some Worker..

  this.setState((prevState) => ({
  year: funcHandleYear(),
  month: funcHandleMonth()
}));

goNextMonth = async () => {
  await this.changeStateFunction();
  const history = createBrowserHistory();
  history.Push(`/calendar?year=${this.state.year}&month=${this.state.month}`);
}

goPrevMonth = async () => {
  await this.changeStateFunction();
  const history = createBrowserHistory();
  history.Push(`/calendar?year=${this.state.year}&month=${this.state.month}`);
}
0
Ritwik

簡単に言えば - this.setState({data:value})は本質的に非同期であり、コールスタックから移動し、解決されない限りコールスタックに戻るだけです。

Event Loopについて読んで、JSの非同期性についての明確な説明と、更新に時間がかかる理由 -

https://medium.com/front-end-weekly/javascript-event-loop-explained-4cd26af121d4

だから -

    this.setState({data:value});
    console.log(this.state.data); // will give undefined or unupdated value

更新には時間がかかります。上記のプロセスを達成するために -

    this.setState({data:value},function () {
     console.log(this.state.data);
    });
0
Vishal Bisht