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.function counter(state = 0, action)ofunction visibleIds(state = [], action).En pocas palabras: es Redux el que pasa el estado inicial a los reductores, no necesitas hacer nada.
Cuando llama,
createStore(reducer, [initialState])le está haciendo saber a Redux cuál es el estado inicial que se pasará al reductor cuando entre la primera acción.La segunda opción que mencionas, se aplica solo en caso de que no hayas pasado un estado inicial al crear la tienda. es decir
function todoApp(state = initialState, action)el estado solo se inicializará si no hubo ningún estado pasado por Redux
fuente
menuState, ¿cómo le digo al reductor de menú que lea el valor destate.menude la tienda y lo use como su estado inicial?combineReducers () hace el trabajo por usted. La primera forma de escribirlo no es realmente útil:
const rootReducer = combineReducers({ todos, users })Pero el otro, que es equivalente, es más claro:
function rootReducer(state, action) { todos: todos(state.todos, action), users: users(state.users, action) }fuente
Espero que esto responda a su solicitud (que entendí como inicializar reductores al pasar intialState y devolver ese estado)
Así es como lo hacemos (advertencia: copiado del código Typecript).
La esencia es la
if(!state)prueba en la función mainReducer (fábrica)function getInitialState(): MainState { return { prop1: 'value1', prop1: 'value2', ... } } const reducer = combineReducers( { main: mainReducer( getInitialState() ), ... } ) const mainReducer = ( initialState: MainState ): Reducer => { return ( state: MainState, action: Action ): MainState => { if ( !state ) { return initialState } console.log( 'Main reducer action: ', action ) switch ( action.type ) { .... } } }fuente