TL; DR
Sin combineReducers()código manual o similar, initialStatesiempre gana state = ...en el reductor porque lo que se statepasa al reductor es initialState y no es undefined , por lo que la sintaxis del argumento ES6 no se aplica en este caso.
Con combineReducers()el comportamiento es más matizado. Los reductores cuyo estado se especifica en initialStaterecibirán eso state. Otros reductores recibirán undefined y, debido a eso , volverán al state = ...argumento predeterminado que especifican.
En general, initialStategana el estado especificado por el reductor. Esto permite que los reductores especifiquen datos iniciales que tengan sentido para ellos como argumentos predeterminados, pero también permite cargar datos existentes (total o parcialmente) cuando está hidratando la tienda desde algún almacenamiento persistente o el servidor.
Primero, consideremos un caso en el que tiene un solo reductor.
Di que no usas combineReducers().
Entonces su reductor podría verse así:
function counter(state = 0, action) {
switch (action.type) {
case 'INCREMENT': return state + 1;
case 'DECREMENT': return state - 1;
default: return state;
}
}
Ahora digamos que crea una tienda con él.
import { createStore } from 'redux';
let store = createStore(counter);
console.log(store.getState());
El estado inicial es cero. ¿Por qué? Porque el segundo argumento de createStorefue undefined. Este es el statepasado a su reductor la primera vez. Cuando Redux se inicializa, envía una acción "ficticia" para completar el estado. Entonces su counterreductor fue llamado stateigual a undefined. Este es exactamente el caso que "activa" el argumento predeterminado. Por lo tanto, stateahora tiene 0el statevalor predeterminado ( state = 0). Se 0devolverá este estado ( ).
Consideremos un escenario diferente:
import { createStore } from 'redux';
let store = createStore(counter, 42);
console.log(store.getState());
¿Por qué es 42y no 0esta vez? Porque createStorefue llamado con 42como segundo argumento. Este argumento se statepasa a su reductor junto con la acción ficticia. Esta vez, stateno está indefinido (¡lo está 42!), Por lo que la sintaxis del argumento predeterminado de ES6 no tiene ningún efecto. El statees 42y 42se devuelve del reductor.
Ahora consideremos un caso en el que usa combineReducers().
Tienes dos reductores:
function a(state = 'lol', action) {
return state;
}
function b(state = 'wat', action) {
return state;
}
El reductor generado por combineReducers({ a, b })tiene este aspecto:
function combined(state = {}, action) {
return {
a: a(state.a, action),
b: b(state.b, action)
};
}
Si llamamos createStoresin el initialState, se inicializará el statea {}. Por tanto, state.ay state.bserá undefineden el momento en que llame ay breduzca. Tanto ay breductores recibirán undefinedcomo sus state argumentos, y si especifican por defecto statelos valores, los que serán devueltos. Así es como el reductor combinado devuelve un { a: 'lol', b: 'wat' }objeto de estado en la primera invocación.
import { createStore } from 'redux';
let store = createStore(combined);
console.log(store.getState());
Consideremos un escenario diferente:
import { createStore } from 'redux';
let store = createStore(combined, { a: 'horse' });
console.log(store.getState());
Ahora especifiqué initialStatecomo argumento createStore(). El estado devuelto por el reductor combinado combina el estado inicial que especifiqué para el areductor con el 'wat'argumento predeterminado especificado que el breductor eligió a sí mismo.
Recordemos lo que hace el reductor combinado:
function combined(state = {}, action) {
return {
a: a(state.a, action),
b: b(state.b, action)
};
}
En este caso, statese especificó para no volver a {}. Era un objeto con acampo igual a 'horse', pero sin bcampo. Es por eso que el areductor lo recibió 'horse'como statesuyo y lo devolvió con gusto, pero el breductor lo recibió undefinedcomo suyo statey, por lo tanto, devolvió su idea del valor predeterminado state(en nuestro ejemplo, 'wat'). Así es como recibimos { a: 'horse', b: 'wat' }a cambio.
En resumen, si se apega a las convenciones de Redux y devuelve el estado inicial de los reductores cuando se llaman con undefinedel stateargumento (la forma más fácil de implementar esto es especificar el statevalor del argumento predeterminado de ES6), tendrá un buen comportamiento útil para reductores combinados. Preferirán el valor correspondiente en el initialStateobjeto que pasa a la createStore()función, pero si no pasó ninguno, o si el campo correspondiente no está configurado, statese elige el argumento predeterminado especificado por el reductor.Este enfoque funciona bien porque proporciona tanto la inicialización como la hidratación de los datos existentes, pero permite que los reductores individuales restablezcan su estado si sus datos no se conservaron. Por supuesto, puede aplicar este patrón de forma recursiva, como puede utilizar combineReducers()en muchos niveles, o incluso componer reductores manualmente llamando a los reductores y dándoles la parte relevante del árbol de estado.
combineReducers. Muchisímas gracias de nuevo.