TL; DR
Senza combineReducers()
o simile codice manuale, initialState
vince sempre state = ...
nel riduttore perché il state
passato 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 initialState
lo riceveranno state
. Gli altri riduttori riceveranno undefined
e per questo motivo torneranno state = ...
all'argomento predefinito specificato.
In generale, initialState
vince 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 createStore
era undefined
. Questa è state
la prima volta che passi al tuo riduttore. Quando Redux si inizializza, invia un'azione "fittizia" per riempire lo stato. Quindi il tuo counter
riduttore è stato chiamato con state
uguale a undefined
. Questo è esattamente il caso in cui "attiva" l'argomento predefinito. Pertanto, state
è ora 0
come per il state
valore 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é è createStore
stato chiamato con 42
come secondo argomento. Questo argomento diventa il state
passato al tuo riduttore insieme all'azione fittizia. Questa volta state
non è undefined (lo è 42
!), Quindi la sintassi degli argomenti predefinita di ES6 non ha effetto. Il state
è 42
e 42
viene 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 createStore
senza initialState
, inizializzerà il file state
a {}
. Pertanto, state.a
e state.b
sarà undefined
per il momento in cui chiama a
e b
riduzioni. Sia a
e b
riduttori riceveranno undefined
come i loro state
argomenti, e se specificano predefiniti state
valori, 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 initialState
come argomento per createStore()
. Lo stato restituito dal riduttore combinato combina lo stato iniziale specificato per il a
riduttore con l' 'wat'
argomento predefinito specificato dal b
riduttore 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, è state
stato specificato in modo da non ricadere su {}
. Era un oggetto con a
campo uguale a 'horse'
, ma senza b
campo. Questo è il motivo per cui il a
riduttore ha ricevuto 'horse'
come suo state
e lo ha restituito volentieri, ma il b
riduttore ha ricevuto undefined
come suo state
e 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 undefined
come state
argomento (il modo più semplice per implementarlo è specificare il state
valore dell'argomento predefinito di ES6), avrai un bel comportamento utile per i riduttori combinati. Preferiranno il valore corrispondente initialState
nell'oggetto che passi alla createStore()
funzione, ma se non ne hai passato nessuno, o se il campo corrispondente non è impostato, state
viene 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.