mientras trabajo en una aplicación de comercio electrónico, necesito calcular el total de artículos en el carrito. El carrito se guarda en la tienda redux, y el estado de conteo también está allí para contar los artículos.
He probado diferentes soluciones como:
1)Reducción del estado.carro en el Reductor de Carro. Pero esto no funcionó bien ya que traté de reducir el estado.carro en cada elemento agregado o eliminado del estado.carro Y no está tomando el valor inmediato del estado.carro, por lo tanto, no elimina los elementos correspondientemente. Como sigue
if(action.type === ADD_TO_CART) { return { ...state, cartItems: action.payload, total : state.cartItems.reduce((acc,val) =>{ acc += val.count; return acc },0) } } else if(action.type === REMOVE_FROM_CART){ return { ...state, cartItems: action.payload, total : state.cartItems.reduce((acc,val) =>{ acc += val.count; return acc },0) } }2) En segundo lugar, creo un creador de acciones getTotal() y lo envío desde el gancho useEffect. Está funcionando totalmente bien, pero el único problema que creo que es importante, la consola está dando un error de pila de llamadas de profundidad máxima.
Archivo action.js
export const getTotal = () => dispatch =>{ return dispatch({type: GET_TOTAL}) }archivo reductor.js
else if(action.type === GET_TOTAL){ return { ...state, total: state.cartItems.reduce((acc,val) =>{ acc += val.count; return acc },0) } }Archivo Navbar.js
useEffect(() =>{ dispatch(getTotal()) }) // ------- <Link to="/cart"> <Badge badgeContent={total} color="primary"> <ShoppingCartOutlined /> </Badge> </Link>Entonces, ¿cuál es la mejor manera de calcular el total de artículos en el carrito o si de alguna manera puedo manejar el gancho useEffect para evitar el error de la pila de llamadas?
Esperando :) gracias,
Echemos un vistazo a su reductor primero.
if(action.type === ADD_TO_CART) { // Land on a new state // Refine the new state // Return it } }Debe tomarse su tiempo para realizar los tres pasos anteriores, la razón por la que no funciona es que lo hizo demasiado rápido :)
const newState = { ...state, cartItems.action.payload } newState.total = newState.cartItems.reduce((acc,val) =>{ acc += val.count; return acc },0) return newState } No importa cómo lo haga, concéntrese en newState not state . Parece que todo se puede hacer en un solo paso, pero hay un orden de las cosas a las que debes prestar atención.
No utilice el dispatch para valores calculados.
En su lugar, cree una función auxiliar para la lógica de cálculo:
const getCartTotal = ({cartItems}) => { return cartItems.reduce((acc,val) =>{ acc += val.count; return acc; } };En componente:
const cart = useSelector(state => state.cart); const total = getCartTotal(cart); <Link to="/cart"> <Badge badgeContent={total} color="primary"> <ShoppingCartOutlined /> </Badge> </Link>Puede crear selectores para el carrito y el total del carrito:
import {createSelector} from 'reselect'; // if you're already using @reduxjs/toolkit: // import {createSelector} from '@reduxjs/toolkit'; const cartSelector = (state) => state.cart; const cartTotalSelector = createSelector( cartSelector, state => getCartTotal(state); );En componente:
const total = useSelector(cartTotalSelector);Como práctica recomendada, la tienda no debe calcular nada, sino inferir el siguiente estado del actual y combinarlos según sea necesario a través de la carga útil de la acción.
import { ADD_TO_CART, EMPTY_CART, REMOVE_FROM_CART } from '../actions/types'; const initialState = { cart: [], count: 0, } export default function(state=initialState, action) { switch(action.type){ case ADD_TO_CART: return { ...state, cart: [action.payload, ...state.cart], count: state.count + 1 } case EMPTY_CART: return { ...state, cart: [], count: 0 } case REMOVE_FROM_CART: return { ...state, cart: state.cart.filter((item, i) => i !== action.payload.index), count: state.count - 1 } default: return state } }