TL; DR
Senza combineReducers()o simile codice manuale, initialStatevince sempre state = ...nel riduttore perché il statepassato al riduttore è initialState e non lo è undefined , quindi la sintassi dell'argomento ES6 non viene applicata in questo caso.
Con combineReducers()il comportamento è più sfumato. Quei riduttori il cui stato è specificato in initialStatelo riceveranno state. Gli altri riduttori riceveranno undefined e per questo motivo torneranno state = ...all'argomento predefinito specificato.
In generale, initialStatevince sullo stato specificato dal riduttore. Ciò consente ai riduttori di specificare i dati iniziali che hanno senso per loro come argomenti predefiniti, ma consente anche di caricare i dati esistenti (completamente o parzialmente) quando si idrata l'archivio da una memoria persistente o dal server.
Per prima cosa consideriamo un caso in cui hai un solo riduttore.
Dì che non usi combineReducers().
Quindi il tuo riduttore potrebbe assomigliare a questo:
function counter(state = 0, action) {
switch (action.type) {
case 'INCREMENT': return state + 1;
case 'DECREMENT': return state - 1;
default: return state;
}
}
Supponiamo ora che crei un negozio con esso.
import { createStore } from 'redux';
let store = createStore(counter);
console.log(store.getState());
Lo stato iniziale è zero. Perché? Perché il secondo argomento createStoreera undefined. Questa è statela prima volta che passi al tuo riduttore. Quando Redux si inizializza, invia un'azione "fittizia" per riempire lo stato. Quindi il tuo counterriduttore è stato chiamato con stateuguale a undefined. Questo è esattamente il caso in cui "attiva" l'argomento predefinito. Pertanto, stateè ora 0come per il statevalore predefinito ( state = 0). Questo stato ( 0) verrà restituito.
Consideriamo uno scenario diverso:
import { createStore } from 'redux';
let store = createStore(counter, 42);
console.log(store.getState());
Perché è 42, e non 0, questa volta? Perché è createStorestato chiamato con 42come secondo argomento. Questo argomento diventa il statepassato al tuo riduttore insieme all'azione fittizia. Questa volta statenon è undefined (lo è 42!), Quindi la sintassi degli argomenti predefinita di ES6 non ha effetto. Il stateè 42e 42viene restituito dal riduttore.
Consideriamo ora un caso in cui utilizzi combineReducers().
Hai due riduttori:
function a(state = 'lol', action) {
return state;
}
function b(state = 'wat', action) {
return state;
}
Il riduttore generato da si combineReducers({ a, b })presenta così:
function combined(state = {}, action) {
return {
a: a(state.a, action),
b: b(state.b, action)
};
}
Se chiamiamo createStoresenza initialState, inizializzerà il file statea {}. Pertanto, state.ae state.bsarà undefinedper il momento in cui chiama ae briduzioni. Sia ae briduttori riceveranno undefinedcome i loro state argomenti, e se specificano predefiniti statevalori, quelli saranno restituiti. Questo è il modo in cui il riduttore combinato restituisce un { a: 'lol', b: 'wat' }oggetto di stato alla prima chiamata.
import { createStore } from 'redux';
let store = createStore(combined);
console.log(store.getState());
Consideriamo uno scenario diverso:
import { createStore } from 'redux';
let store = createStore(combined, { a: 'horse' });
console.log(store.getState());
Ora ho specificato initialStatecome argomento per createStore(). Lo stato restituito dal riduttore combinato combina lo stato iniziale specificato per il ariduttore con l' 'wat'argomento predefinito specificato dal briduttore stesso.
Ricordiamo cosa fa il riduttore combinato:
function combined(state = {}, action) {
return {
a: a(state.a, action),
b: b(state.b, action)
};
}
In questo caso, è statestato specificato in modo da non ricadere su {}. Era un oggetto con acampo uguale a 'horse', ma senza bcampo. Questo è il motivo per cui il ariduttore ha ricevuto 'horse'come suo statee lo ha restituito volentieri, ma il briduttore ha ricevuto undefinedcome suo statee quindi ha restituito la sua idea di default state(nel nostro esempio 'wat'). Ecco come otteniamo { a: 'horse', b: 'wat' }in cambio.
Per riassumere, se ti attieni alle convenzioni Redux e restituisci lo stato iniziale dai riduttori quando vengono chiamati con undefinedcome stateargomento (il modo più semplice per implementarlo è specificare il statevalore dell'argomento predefinito di ES6), avrai un bel comportamento utile per i riduttori combinati. Preferiranno il valore corrispondente initialStatenell'oggetto che passi alla createStore()funzione, ma se non ne hai passato nessuno, o se il campo corrispondente non è impostato, stateviene invece scelto l' argomento predefinito specificato dal riduttore.Questo approccio funziona bene perché fornisce sia l'inizializzazione che l'idratazione dei dati esistenti, ma consente ai singoli riduttori di ripristinare il proprio stato se i dati non sono stati conservati. Ovviamente puoi applicare questo modello in modo ricorsivo, poiché puoi usarlo combineReducers()su molti livelli, o anche comporre manualmente i riduttori chiamando i riduttori e dando loro la parte rilevante dell'albero degli stati.
combineReducers. Grazie mille ancora.