react form javascript reactjs redux

javascript - form - redux saga



Reductores reductores-cambiando el estado profundamente anidado (3)

Estoy tratando de envolver mi cabeza en torno a cómo cambiar el estado profundamente anidado en redux. Para mí tiene sentido combinar reductores y cambiar las propiedades de primer nivel del estado para esas piezas. Donde no estoy tan claro es sobre cómo cambiar el estado de una propiedad profundamente anidada. Vamos a pretender que tengo una aplicación de carrito de compras. A continuación se muestra mi estado:

{ cart: { items: [] }, account: { amountLeft: 100, discounts: { redeemed: [], coupons: { buyOneGetOne: false } } } }

Cuando un usuario ingresa un código, supongamos que puede canjear el cupón "buyOneGetOne" y ese valor debería convertirse en verdadero. Tengo un reductor para carrito y otro para cuenta. Para una propiedad de primer nivel (como si estuviera limpiando los artículos del carro), solo haría lo siguiente en mi reductor:

case ''EMPTY_CART'': return Object.assign({}, state, {items: []});

Para cambiar buyOneGetOne, sin embargo, parece que primero tendría que hacer un Object.assign en cupones (porque se modificó buyOneGetOne), luego hacer un Object.assign en descuentos (porque tenía cupones modificados) y, finalmente, emitir la acción. por lo que el reductor podría hacer Object.assign en la cuenta (porque los descuentos ahora han cambiado). Sin embargo, esto parece realmente complicado y fácil de hacer mal, lo que me lleva a creer que debe haber una mejor manera.

¿Estoy yendo todo esto mal? Parece que los reductores solo se usan para modificar las propiedades de nivel raíz del estado (como el carrito y la cuenta) y que no debería tener un reductor que toque el estado dentro de la cuenta (como un reductor de descuentos), porque la cuenta ya tiene un reductor . Pero cuando solo quiero cambiar una propiedad a lo largo del árbol de estado, se vuelve complejo fusionar cada objeto desde ese cambio hasta la cadena de objetos del hijo de la raíz ...

¿Puede / debería tener reductores dentro de los reductores, como en este caso tener un reductor de descuentos?


Debes anidar Reductores combinedReducers para cada nivel de profundidad.


Definitivamente puedes tener reductores dentro de los reductores; de hecho, la aplicación de demostración de redux hace esto: http://redux.js.org/docs/basics/Reducers.html .

Por ejemplo, podría hacer un reductor anidado llamado `descuentos '':

function discounts(state, action) { switch (action.type) { case ADD_DISCOUNT: return state.concat([action.payload]); // etc etc } }

Y luego haga uso de este reductor en su reductor de cuenta:

function account(state, action) { switch (action.type) { case ADD_DISCOUNT: return { ...state, discounts: discounts(state.discounts, action) }; // etc etc } }

Para obtener más información, echa un vistazo a la serie redhead de egghead.io del propio Dan, ¡específicamente el video de composición reductora !


Sí, separar esos reductores es una cosa correcta. En realidad, si tiene miedo de que algunas de esas acciones requieran el cambio de otro reductor, puede reaccionar a otra constante o simplemente despachar otra acción.

He creado una biblioteca para abordar este problema: para permitir una composición fácil y para evitar una sintaxis detallada, junto con la fusión de resultados. Entonces, tu ejemplo se verá así:

import { createTile, createSyncTile } from ''redux-tiles''; const cartItems = createSyncTile({ type: [''account'', ''cart''], fn: ({ params }) => ({ items: params.items }) }); const coupons = createSyncTile({ type: [''account'', ''coupons''], fn: ({ params }) => params, }); const reedemedCoupons = createSyncTile({ type: [''account'', ''reedemedCoupons''], fn: ({ params }) => params.coupons }); const account = createTile({ type: [''account'', ''info''], fn: ({ api }) => api.get(''/client/info'') });

Al usar esta estrategia, cada componente es atómico, y puede crear nuevos y enviar otros fácilmente, sin afectar a otros, hace que sea más fácil refactorizar y eliminar alguna funcionalidad en el futuro, cuando sus "fichas" sigan un principio de responsabilidad única.