export const itemReducer = (state, action) => { switch (action.type) { default: return state } } import React, { useState, useReducer, createContext, useContext } from 'react' import { useQuery } from '@apollo/client' import { CURRENT_MONTH_BY_USER } from '../graphql/queries' import { itemReducer } from '../reducers/ItemReducer' const Items = createContext() export const ItemProvider = ({ children }) => { let items = [] const [state, dispatch] = useReducer(itemReducer, { items: items }) const result = useQuery(CURRENT_MONTH_BY_USER) if (result.data && result.data.getCurrentMonthByUser) { items = [...result.data.getCurrentMonthByUser] } return <Items.Provider value={{ state, dispatch }}>{children}</Items.Provider> } export const ItemsState = () => { return useContext(Items) } export default ItemProvider let items obtiene datos correctos de useQuery , sin embargo, no se pasa nada al estado, por lo tanto, no puedo transferir datos a otros componentes desde el contexto. ¿Qué estoy haciendo mal aquí?
Al depurar tanto los items como state , inicialmente están vacíos debido a la carga; sin embargo, solo los items reciben los datos correctos y el estado permanece como una matriz vacía.
Si coloco datos estáticos en let items , funciona bien, así que tal vez también pueda haber algún problema con mi useQuery .
Es fácil ver su problema si observa dónde se usan items . Eso es solo como el estado inicial de su llamada useReducer , pero items solo se establecen en un valor no vacío después de esto. Eso no tiene absolutamente ningún efecto en el componente, porque los items no se usan más adelante en la función de su componente, y el estado inicial solo se establece una vez, en el primer renderizado.
Para resolver esto, debe adoptar el uso de un reductor, agregar un nuevo tipo de acción para establecer estos datos iniciales y luego enviarlos cuando tenga los datos. Así que agregue algo como esto a su reductor:
export const itemReducer = (state, action) => { switch (action.type) { case SET_INITIAL_DATA: // only a suggestion for the name, and obviously you need to define this as a constant return { ...state, items: action.items }; /* other actions here */ default: return state } }y luego reescriba su componente de esta manera:
export const ItemProvider = ({ children }) => { const [state, dispatch] = useReducer(itemReducer, { items: [] }) const result = useQuery(CURRENT_MONTH_BY_USER) if (result.data && result.data.getCurrentMonthByUser) { dispatch({ type: SET_INITIAL_DATA, items: result.data.getCurrentMonthByUser }); } return <Items.Provider value={{ state, dispatch }}>{children}</Items.Provider> } Además, si bien esto no está relacionado con su pregunta, notaré que su exportación de ItemsState parece ser un gancho personalizado (no puede ser otra cosa ya que no es un componente pero usa un gancho) - eso está perfectamente bien pero no Es una convención muy fuerte en React que todos los ganchos personalizados tienen nombres de la forma useXXX , que le sugiero que siga. Por lo tanto, podría cambiar el nombre de esto a algo como useItemsState (preferiría useItemsContext para dejar en claro que es solo un useContext especializado en su contexto específico).