Soy nuevo en React y trato de crear una aplicación con una función de carrito donde los usuarios pueden agregar robots al carrito. Estoy usando la Context API para proporcionar un carrito en la aplicación y useReducer para los estados. Los robots se obtienen de un servidor y se cargan correctamente. Pero parece que no puedo encontrar una manera de establecer el estado inicial del reducer usando productos obtenidos. El estado siempre devuelve una matriz vacía para robots. ¿Cómo resolver esto?
const CartProvider = ({ children }) => { const [robots, setRobots] = useState([]); useEffect(() => { fetch('http://localhost:8000/api/robots') .then(res => res.json()) .then(data => setRobots(data?.data)) }, []) const initialState = { robots: [...robots], cart: [] } const [state, dispatch] = useReducer(cartReducer, initialState); return ( <CartContext.Provider value={{ state, dispatch }}> {children} </CartContext.Provider> ); } export default CartProvider;const [state, dispatch] = useReducer(cartReducer, initialState); useReducer no monitoreará los cambios en initialState , solo considerará su valor inicial. Simplemente puede enviar una acción para actualizar el estado una vez que se obtienen los datos.
const initialState = { robots: [], cart: [] } const CartProvider = ({ children }) => { const [state, dispatch] = useReducer(cartReducer, initialState); useEffect(() => { fetch('http://localhost:8000/api/robots') .then(res => res.json()) .then(data => { // dispatch action to update the reducer state }) }, []) return ( <CartContext.Provider value={{ state, dispatch }}> {children} </CartContext.Provider> ); } export default CartProvider;Si los componentes anidados no funcionan bien hasta que se completa el estado, puede representar el proveedor de forma condicional:
return ( <> {state.robots.length && ( <CartContext.Provider value={{ state, dispatch }}> {children} </CartContext.Provider> )} </> );Dado que el valor del estado inicial se obtiene de forma asíncrona, deberá enviar una acción para establecer el valor del state .
Ejemplo:
const cartReducer = (state, action) => { switch(action.type) { ... other reducer cases ... case 'INITIALIZE_CART': return action.payload; default: return state; } };ProveedorCarrito
const initialState = { robots: [], cart: [] }; const CartProvider = ({ children }) => { const [robots, setRobots] = useState([]); const [state, dispatch] = useReducer(cartReducer, initialState); useEffect(() => { fetch('http://localhost:8000/api/robots') .then(res => res.json()) .then(data => { dispatch({ type: 'INITIALIZE_CART', payload: { ...initialState, robots: data?.data, } }); }); }, []); return ( <CartContext.Provider value={{ state, dispatch }}> {children} </CartContext.Provider> ); };Es común también mantener algún estado en el estado de inicialización de la aplicación. La interfaz de usuario se representa condicionalmente en función de este valor de estado.
Ejemplo:
const initialState = { initialized: false, robots: [], cart: [] };...
const cartReducer = (state, action) => { switch(action.type) { ... other reducer cases ... case 'INITIALIZE_CART': return { ...action.payload, initialized: true, }; default: return state; } };