ReactJS — setState() не отражает изменения немедленно

#javascript #reactjs #setstate

#javascript #reactjs #setstate

Вопрос:

Мой код выглядит следующим образом :

 import React, { Component } from 'react';

class Counter extends Component {

    constructor() {
        super();
        this.state = {
            counter : 0
        }
    }


    increment() {
        const { counter } = this.state;
        this.setState({counter : counter 1 });
        console.log(counter);
    }


    render() {
        const { counter} = this.state;
        return (
            <div>
                <h1> {counter} </h1>
                <button onClick={() => this.increment()}>Click Me</button>
            </div>
        );
    }
}

export default Counter;
 

У меня есть простой h1 и кнопка. Поведение программы должно заключаться в том, что когда я нажимаю кнопку, значение счетчика должно увеличиваться на 1 (как на веб-странице, так и на консоли, поскольку я также печатаю значение счетчика в консоли). Проблема в том, что когда я нажимаю кнопку, значение изменяется с 0 на 1 на моей веб-странице, но в моей консоли я по-прежнему вижу значение counter как 0 (вместо 1), когда я нажимаю кнопку во второй раз, значение изменяется с 1 на 2 на моей веб-странице, но в моей консолизначение изменяется с 0 на 1 (вместо 2). Может кто -нибудь , пожалуйста, сказать мне , что происходит ?

Комментарии:

1. Итак, что я должен сделать, чтобы получить желаемый результат?

2. Можете ли вы сказать мне, как это сделать?

3. Есть ли какой-либо другой способ без использования prevCounter?

4. В моем первом комментарии была ошибка, ниже приведен правильный способ обновления состояния в вашем случае: this.setState(prevState => ({ counter: prevState.counter 1 }), () => console.log(counter));

5. Оба ответа верны в отношении асинхронного характера setState . Но в вашем случае здесь, даже если бы это было полностью синхронно, вы бы просто записали старое значение из-за первоначального назначения деструктурирования. Поскольку state.counter это скалярное значение, вы фактически скопировали это значение в counter переменную. Любые state.counter последующие изменения не будут отражены. Демонстрация: jsfiddle.net/vf1kwnuc

Ответ №1:

this.setState() это асинхронная функция, поэтому выполняется в фоновом режиме, пока она переходит к следующей строке. Чтобы запустить код после setState(), вам нужен обратный вызов — так что в вашем примере это будет:

 this.setState(prevState => ({ counter: prevState.counter   1 }), () => console.log(counter)); // the console.log() will only run after the setState is finished!
 

Его легко забыть о его асинхронности, потому что это часто происходит так быстро, что вы можете console.log() сразу же после этого изменить состояние!

Ответ №2:

Действия setState являются асинхронными и группируются для повышения производительности. Это объясняется в документации setState.

setState() не сразу изменяет this.state, а создает ожидающий переход состояния. Доступ к this.state после вызова этого метода потенциально может вернуть существующее значение. Нет гарантии синхронной работы вызовов setState, и вызовы могут группироваться для повышения производительности.

Вы можете использовать обратный вызов setState, чтобы найти немедленные изменения, или вы можете использовать componentDidUpdate

 this.setState({ counter : counter 1 }, newState => {
   console.log(newState.counter)
});

 

или

 componentDidUpdate(prevProps, prevState) {
  console.log(this.state) // New State
  console.log(prevState) // Previous State
  if (this.state.counter !== prevState.counter) {
    // counter changed
  }
}