Immaginate incrementare un contatore in qualche 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>
...
)
}
}
C'è un gestore di conteggio collegato sia al genitore e i componenti figlio. Questo è fatto apposta per poter eseguire setState() due volte all'interno dello stesso contesto di bubbling di un evento click, ma da 2 diversi gestori.
Come si potrebbe immaginare, un evento con un solo clic sul pulsante attiverà ora entrambi questi gestori poiché le bolle di eventi dal target al contenitore più esterno durante la fase di bubbling.
Quindi il btnCountHandler() eseguito per primo, prevede di incrementare il conteggio a 1 e poi la divCountHandler() esegue, prevede di incrementare il conteggio a 2.
Tuttavia il conteggio incrementa solo per 1 come è possibile ispezionare in strumenti React Developer.
Ciò dimostra che reagiscono
code chiama tutte le setState
torna a questa coda dopo l'esecuzione l'ultimo metodo nel contesto (la divCountHandler in questo caso)
unisce tutte le mutazioni di oggetti che si verificano all'interno di più chiamate setState nello stesso contesto (tutte le chiamate di metodo all'interno di una singola fase di evento è lo stesso contesto per es.) in una sintassi di mutazione di un singolo oggetto (la fusione rende sens E perché questo è il motivo per cui possiamo aggiornare le proprietà di stato in modo indipendente in setState() in primo luogo)
e lo passa in un singolo setState() per impedire il re-rendering a causa di più chiamate setState() (questo è una descrizione molto primitiva del dosaggio).
codice risultante gestito da reagire:
this.setState({
updatedByDiv: 'Div',
updatedByBtn: 'Button',
counter: this.state.counter + 1
})
Per interrompere questo comportamento, invece di passare oggetti come argomenti al metodo setState, vengono passati callback.
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');
}
Dopo l'ultimo metodo termina l'esecuzione e quando ritorna reagire per elaborare la coda setState, chiama semplicemente il callback per ogni setState coda, passando nel precedente stato del componente.
In questo modo reagisce assicurando che l'ultimo richiamo in coda arrivi ad aggiornare lo stato su cui tutte le sue precedenti controparti hanno posto le mani.
Vedere http://stackoverflow.com/questions/28922275/in-reactjs-why-does-setstate-behave-differently-when-called-synchronous – lux