Imagine incrementar um contador em algum componente:
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>
...
)
}
}
Há um manipulador de contagem anexado aos componentes pai e filho. Isso é feito propositadamente, para que possamos executar o setState () duas vezes no mesmo contexto de bolhas de eventos de clique, mas dentro de dois manipuladores diferentes.
Como poderíamos imaginar, um evento de clique único no botão agora acionaria esses dois manipuladores, pois o evento passa do alvo para o contêiner mais externo durante a fase de bolhas.
Portanto, o btnCountHandler () é executado primeiro, com o objetivo de incrementar a contagem para 1 e, em seguida, o divCountHandler () é executado, com o objetivo de incrementar a contagem para 2.
No entanto, a contagem apenas aumenta para 1, como você pode inspecionar nas ferramentas do React Developer.
Isso prova que reagem
enfileira todas as chamadas setState
volta para esta fila depois de executar o último método no contexto (o divCountHandler neste caso)
mescla todas as mutações de objetos que ocorrem em várias chamadas setState no mesmo contexto (todas as chamadas de métodos em uma única fase de evento são o mesmo contexto, por exemplo) em uma sintaxe de mutação de um único objeto (a fusão faz sentido porque é por isso que podemos atualizar as propriedades do estado independentemente em setState () em primeiro lugar)
e o passa para um único setState () para evitar a nova renderização devido a várias chamadas setState () (esta é uma descrição muito primitiva do lote).
Código resultante executado por react:
this.setState({
updatedByDiv: 'Div',
updatedByBtn: 'Button',
counter: this.state.counter + 1
})
Para interromper esse comportamento, em vez de passar objetos como argumentos para o método setState, retornos de chamada são passados.
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');
}
Depois que o último método conclui a execução e quando o react retorna para processar a fila setState, ele simplesmente chama o retorno de chamada para cada setState na fila, passando no estado anterior do componente.
Dessa maneira, o React garante que o último retorno de chamada na fila atualize o estado em que todos os seus colegas anteriores se comprometeram.