Представьте, что в каком-то компоненте увеличивается счетчик:
class SomeComponent extends Component{
state = {
updatedByDiv: '',
updatedByBtn: '',
counter: 0
}
divCountHandler = () => {
this.setState({
updatedByDiv: 'Div',
counter: this.state.counter + 1
});
console.log('divCountHandler executed');
}
btnCountHandler = () => {
this.setState({
updatedByBtn: 'Button',
counter: this.state.counter + 1
});
console.log('btnCountHandler executed');
}
...
...
render(){
return (
...
// a parent div
<div onClick={this.divCountHandler}>
// a child button
<button onClick={this.btnCountHandler}>Increment Count</button>
</div>
...
)
}
}
К родительскому и дочернему компонентам прикреплен обработчик счетчика. Это сделано специально, чтобы мы могли дважды выполнить setState () в одном контексте восходящей цепочки событий щелчка, но из двух разных обработчиков.
Как мы могли предположить, событие одиночного щелчка на кнопке теперь запускает оба этих обработчика, поскольку событие перемещается от цели к самому внешнему контейнеру во время фазы восходящей цепочки.
Следовательно, сначала выполняется btnCountHandler (), ожидаемый для увеличения счетчика до 1, а затем выполняется divCountHandler (), ожидаемый для увеличения счетчика до 2.
Однако счетчик увеличивается только до 1, как вы можете проверить в инструментах React Developer.
Это доказывает, что реагировать
ставит в очередь все вызовы setState
возвращается в эту очередь после выполнения последнего метода в контексте (в данном случае divCountHandler)
объединяет все мутации объекта, происходящие в нескольких вызовах setState в одном контексте (все вызовы методов в рамках одной фазы события имеют один и тот же контекст, например) в один синтаксис мутации одного объекта (слияние имеет смысл, потому что именно поэтому мы можем обновлять свойства состояния независимо в setState () в первую очередь)
и передает его в один единственный setState (), чтобы предотвратить повторный рендеринг из-за нескольких вызовов setState () (это очень примитивное описание пакетной обработки).
Результирующий код, запускаемый реакцией:
this.setState({
updatedByDiv: 'Div',
updatedByBtn: 'Button',
counter: this.state.counter + 1
})
Чтобы остановить это поведение, вместо передачи объектов в качестве аргументов методу setState передаются обратные вызовы.
divCountHandler = () => {
this.setState((prevState, props) => {
return {
updatedByDiv: 'Div',
counter: prevState.counter + 1
};
});
console.log('divCountHandler executed');
}
btnCountHandler = () => {
this.setState((prevState, props) => {
return {
updatedByBtn: 'Button',
counter: prevState.counter + 1
};
});
console.log('btnCountHandler executed');
}
После того, как последний метод завершает выполнение и когда response возвращается для обработки очереди setState, он просто вызывает обратный вызов для каждого setState в очереди, передавая предыдущее состояние компонента.
Таким образом, реакция гарантирует, что последний обратный вызов в очереди обновит состояние, на которое возложили руки все его предыдущие аналоги.