Lavoro su React.
TLDR:
Ma puoi fidarti di React per aggiornare lo stato nello stesso ordine richiesto per setState
Sì.
Sì.
Il ordine degli aggiornamenti è sempre rispettato. Se vedi uno stato intermedio "tra" o meno dipende dal fatto che tu sia dentro o meno in un batch.
Attualmente (React 16 e precedenti), solo gli aggiornamenti all'interno dei gestori di eventi React sono raggruppati per impostazione predefinita . Esiste un'API instabile per forzare il batch al di fuori dei gestori di eventi in rari casi in cui è necessario.
Nelle versioni future (probabilmente React 17 e successive), React raggrupperà tutti gli aggiornamenti per impostazione predefinita, quindi non dovrai pensarci. Come sempre, annunceremo eventuali modifiche al riguardo sul blog React e nelle note di rilascio.
La chiave per capire questo è che, indipendentemente dal numero di setState()
chiamate in quanti componenti fai all'interno di un gestore di eventi React , alla fine dell'evento produrranno solo un nuovo rendering . Questo è fondamentale per una buona prestazione in applicazioni di grandi dimensioni perché se Child
e Parent
ogni chiamata setState()
durante la gestione di un evento click, non si desidera eseguire il rendering di nuovoChild
due volte.
In entrambi i tuoi esempi, setState()
chiamate avvengono all'interno di un gestore eventi React. Pertanto, vengono sempre uniti insieme alla fine dell'evento (e non si vede lo stato intermedio).
Gli aggiornamenti vengono sempre uniti in modo superficiale nell'ordine in cui si verificano . Quindi, se il primo aggiornamento è {a: 10}
, il secondo è {b: 20}
e il terzo è {a: 30}
, lo stato di rendering sarà {a: 30, b: 20}
. L'aggiornamento più recente alla stessa chiave di stato (ad es. Comea
nel mio esempio) "vince sempre".
L' this.state
oggetto viene aggiornato quando eseguiamo nuovamente il rendering dell'interfaccia utente alla fine del batch. Pertanto, se è necessario aggiornare lo stato in base a uno stato precedente (come l'incremento di un contatore), è necessario utilizzare la setState(fn)
versione funzionale che fornisce lo stato precedente, invece di leggere da this.state
. Se sei curioso del ragionamento per questo, l'ho spiegato in modo approfondito in questo commento .
Nel tuo esempio, non vedremmo lo "stato intermedio" perché siamo all'interno di un gestore eventi React in cui è abilitato il batch (perché React "sa" quando stiamo uscendo da quell'evento).
Tuttavia, sia in React 16 che nelle versioni precedenti, non esiste ancora un batch per impostazione predefinita al di fuori dei gestori di eventi React . Quindi se nel tuo esempio avessimo un gestore di risposte AJAX invece di handleClick
, ognuno setState()
verrebbe elaborato immediatamente in tempo reale. In questo caso, sì, si dovrebbe vedere uno stato intermedio:
promise.then(() => {
// We're not in an event handler, so these are flushed separately.
this.setState({a: true}); // Re-renders with {a: true, b: false }
this.setState({b: true}); // Re-renders with {a: true, b: true }
this.props.setParentState(); // Re-renders the parent
});
Ci rendiamo conto che è scomodo che il comportamento sia diverso a seconda che tu sia o meno in un gestore di eventi . Ciò cambierà in una futura versione di React che impacchetterà tutti gli aggiornamenti per impostazione predefinita (e fornirà un'API opt-in per scaricare le modifiche in modo sincrono). Fino a quando non cambiamo il comportamento predefinito (potenzialmente in React 17), c'è un'API che puoi usare per forzare il batch :
promise.then(() => {
// Forces batching
ReactDOM.unstable_batchedUpdates(() => {
this.setState({a: true}); // Doesn't re-render yet
this.setState({b: true}); // Doesn't re-render yet
this.props.setParentState(); // Doesn't re-render yet
});
// When we exit unstable_batchedUpdates, re-renders once
});
I gestori di eventi internamente di React sono tutti inclusi, unstable_batchedUpdates
motivo per cui sono raggruppati per impostazione predefinita. Si noti che il wrapping di un aggiornamento in unstable_batchedUpdates
due volte non ha alcun effetto. Gli aggiornamenti vengono scaricati quando si esce dalla unstable_batchedUpdates
chiamata più esterna .
Tale API è "instabile", nel senso che la rimuoveremo quando il batch è già abilitato per impostazione predefinita. Tuttavia, non lo rimuoveremo in una versione minore, quindi puoi tranquillamente fare affidamento su di esso fino a React 17 se è necessario forzare il batch in alcuni casi al di fuori dei gestori di eventi React.
Per riassumere, questo è un argomento confuso perché React solo i batch all'interno dei gestori di eventi per impostazione predefinita. Questo cambierà nelle versioni future e il comportamento sarà più semplice allora. Ma la soluzione non è quella di raggruppare meno , ma di raggruppare di più per impostazione predefinita. Questo è quello che faremo.