[英]no data is passed into state when using useContext/useReducer together with useQuery
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
gets correct data from the useQuery , however nothing is passed into the state, therefore I am unable to transfer data into another components from the context. let items
从useQuery获取正确的数据,但是没有任何内容传递到 state,因此我无法将数据从上下文传输到另一个组件。 What am I doing wrong here?我在这里做错了什么?
When debugging both items
and state
they're initially empty because of the loading however then only the items
receives correct data and state remains as empty array.在调试items
和state
时,由于加载,它们最初是空的,但是只有items
接收到正确的数据,而 state 仍然是空数组。
If i put static data into let items
it works just fine, so maybe there can be something wrong with my useQuery as well?如果我将 static 数据放入let items
,它就可以正常工作,所以我的useQuery也可能有问题吗?
It's easy to see your problem if you look at where items
is used.如果您查看items
的使用位置,就很容易看出您的问题。 That's only as the initial state to your useReducer
call - but items
is only set to a non-empty value after this.这只是您的useReducer
调用的初始 state - 但在此之后items
仅设置为非空值。 That has absolutely no effect on the component, because items
is not used later in your component function, and the initial state is only ever set once, on the first render.这对组件绝对没有影响,因为以后不会在您的组件 function 中使用items
,并且初始 state 仅在第一次渲染时设置一次。
To solve this you need to embrace your use of a reducer, adding a new action type to set this initial data, and then dispatching that when you have the data.要解决这个问题,您需要接受 reducer 的使用,添加一个新的操作类型来设置此初始数据,然后在您拥有数据时分派它。 So add something like this to your reducer:所以在你的减速器中添加这样的东西:
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
}
}
and then rewrite your component like this:然后像这样重写你的组件:
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>
}
Also, while this is unrelated to your question, I will note that your ItemsState
export appears to be a custom hook (it can't be anything else since it isn't a component but uses a hook) - that is perfectly fine but there is a very strong convention in React that all custom hooks have names of the form useXXX
, which I strongly suggest you should follow.此外,虽然这与您的问题无关,但我会注意到您的ItemsState
导出似乎是一个自定义挂钩(它不能是其他任何东西,因为它不是一个组件而是使用一个挂钩) - 这很好但是有是 React 中一个非常严格的约定,所有自定义钩子的名称都采用useXXX
形式,我强烈建议您遵循该约定。 So you could rename this something like useItemsState
(I would prefer useItemsContext
to make clear it's just a useContext
hook specialised to your specific context).因此,您可以将其重命名为useItemsState
(我更喜欢useItemsContext
以明确它只是一个专门针对您的特定上下文的useContext
挂钩)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.