#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
}
}