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 itemsobtiene los 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 ambos items, stateinicialmente están vacíos debido a la carga, sin embargo, solo los itemsdatos correctos y el estado permanecen como una matriz vacía.
Si pongo datos estáticos en let itemsél, funciona bien, así que tal vez también pueda haber algún problema con mi useQuery.
Solución del problema
Es fácil ver su problema si observa dónde itemsse usa. Eso es solo como el estado inicial de su useReducerllamada, pero itemssolo se establece en un valor no vacío después de esto. Eso no tiene absolutamente ningún efecto en el componente, porque itemsno se usa 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 ItemsStateexportación 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 hay una convención muy fuerte en React es que todos los ganchos personalizados tienen nombres de la forma useXXX, que le sugiero encarecidamente que siga. Por lo tanto, podría cambiar el nombre de esto de alguna manera useItemsState(preferiría useItemsContextdejar en claro que es solo un useContextenlace especializado para su contexto específico).
No hay comentarios:
Publicar un comentario