uso react immutable espaƱol javascript reactjs redux

javascript - react - Lea el estado inicial de la tienda en Redux Reducer



redux-thunk (4)

TL; DR

Sin combineReducers() o código manual similar, initialState siempre gana sobre state = ... en el reductor porque el state pasado al reductor es initialState y no está 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 initialState recibirán ese state . Otros reductores recibirán undefined y debido a eso volverán al state = ... argumento predeterminado que especifican.

En general, initialState gana sobre el estado especificado por el reductor. Esto permite a los reductores especificar datos iniciales que tienen sentido para ellos como argumentos predeterminados, pero también permite cargar datos existentes (total o parcialmente) cuando se hidrata la tienda desde algún almacenamiento persistente o el servidor.

Primero consideremos un caso en el que tiene un solo reductor.
Digamos que no usa 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 supongamos que crea una tienda con él.

import { createStore } from ''redux''; let store = createStore(counter); console.log(store.getState()); // 0

El estado inicial es cero. ¿Por qué? Porque el segundo argumento para createStore undefined estaba undefined . Este es el state pasado a su reductor la primera vez. Cuando Redux se inicializa, envía una acción "ficticia" para llenar el estado. Por lo tanto, su counter reductor se llamó con un state igual a undefined . Este es exactamente el caso que "activa" el argumento predeterminado. Por lo tanto, el state ahora es 0 según el valor de state predeterminado ( state = 0 ). Este estado ( 0 ) será devuelto.

Consideremos un escenario diferente:

import { createStore } from ''redux''; let store = createStore(counter, 42); console.log(store.getState()); // 42

¿Por qué es 42 , y no 0 , esta vez? Porque se llamó a createStore con 42 como segundo argumento. Este argumento se convierte en el state pasado a su reductor junto con la acción ficticia. Esta vez, el state no está indefinido (¡es 42 !), Por lo que la sintaxis de argumento predeterminada de ES6 no tiene ningún efecto. El state es 42 y el reductor devuelve 42 .

Ahora consideremos un caso en el que usas 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 }) ve así:

// const combined = combineReducers({ a, b }) function combined(state = {}, action) { return { a: a(state.a, action), b: b(state.b, action) }; }

Si llamamos a createStore sin initialState , inicializará el state a {} . Por lo tanto, state.a y state.b estarán undefined en el momento en que llame a reductores b . Los reductores b recibirán undefined como sus argumentos de state , y si especifican valores de state predeterminados, se devolverán. Así es como el reductor combinado devuelve un objeto de estado { a: ''lol'', b: ''wat'' } en la primera invocación.

import { createStore } from ''redux''; let store = createStore(combined); console.log(store.getState()); // { a: ''lol'', b: ''wat'' }

Consideremos un escenario diferente:

import { createStore } from ''redux''; let store = createStore(combined, { a: ''horse'' }); console.log(store.getState()); // { a: ''horse'', b: ''wat'' }

Ahora especifiqué initialState como argumento para createStore() . El estado devuelto por el reductor combinado combina el estado inicial que especifiqué para el reductor a con el argumento predeterminado ''wat'' que especifica que el reductor b eligió a sí mismo.

Recordemos lo que hace el reductor combinado:

// const combined = combineReducers({ a, b }) function combined(state = {}, action) { return { a: a(state.a, action), b: b(state.b, action) }; }

En este caso, se especificó el state para que no volviera a {} . Era un objeto con a campo igual a ''horse'' , pero sin el campo b . Es por eso que el reductor a recibió ''horse'' como su state y lo devolvió con gusto, pero el reductor b recibió undefined como su state y, por lo tanto, devolvió su idea del state predeterminado (en nuestro ejemplo, ''wat'' ). Así es como obtenemos { a: ''horse'', b: ''wat'' } a cambio.

Para resumir esto, si se apega a las convenciones de Redux y devuelve el estado inicial de los reductores cuando se llaman con undefined como argumento de state (la forma más fácil de implementar esto es especificar el valor de argumento predeterminado del state ES6), está Va a tener un buen comportamiento útil para los reductores combinados. Preferirán el valor correspondiente en el objeto initialState que pase a la función createStore() , pero si no pasó ninguno, o si el campo correspondiente no está configurado, se elige el argumento de state 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, ya que puede usar combineReducers() en muchos niveles, o incluso componer reductores manualmente llamando a reductores y dándoles la parte relevante del árbol de estado.

El estado inicial en una aplicación Redux se puede configurar de dos maneras:

Si pasa el estado inicial a su tienda, ¿cómo lee ese estado de la tienda y lo convierte en el primer argumento en sus reductores?


¿Cómo lee ese estado de la tienda y lo convierte en el primer argumento en sus reductores?

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) }


En pocas palabras: es Redux quien pasa el estado inicial a los reductores, no necesita hacer nada.

Cuando llama a createStore(reducer, [initialState]) le está createStore(reducer, [initialState]) Redux cuál es el estado inicial que se debe pasar al reductor cuando entra la primera acción.

La segunda opción que menciona, se aplica solo en caso de que no haya pasado un estado inicial al crear la tienda. es decir

function todoApp(state = initialState, action)

el estado solo se inicializará si Redux no pasó ningún estado


Espero que esto responda a su solicitud (que entendí como inicialización de reductores al pasar intialState y devolver ese estado)

Así es como lo hacemos (advertencia: copiado del código mecanografiado).

La esencia de esto es la prueba if(!state) State) en la función mainReducer (factory)

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 ) { .... } } }