将 useContext/useReducer 与 useQuery 一起使用时,没有数据传递到状态

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 itemsuseQuery 获取正确的数据,但是没有任何内容传递到状态,因此我无法将数据从上下文传输到另一个组件。我在这里做错了什么?

在调试 itemsstate 时,由于加载,它们最初是空的,但是只有 items 接收到正确的数据并且状态保持为空数组。

如果我将静态数据放入 let items 它工作得很好,所以也许我的 useQuery 也有问题?

如果您查看使用 items 的位置,就很容易看出您的问题。这只是您的 useReducer 调用的初始状态 - 但 items 仅设置为 non-empty 值 之后。这对组件绝对没有影响,因为 items 以后不会在您的组件函数中使用,并且初始状态只会在第一次渲染时设置一次。

要解决这个问题,您需要接受 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
  }
}

然后像这样重写你的组件:

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>
}

此外,虽然这与您的问题无关,但我会注意到您的 ItemsState 导出似乎是一个自定义挂钩(它不能是其他任何东西,因为它不是组件而是使用hook) - 这完全没问题,但在 React 中有一个非常严格的约定,即所有自定义挂钩的名称都采用 useXXX 形式,我强烈建议您遵循该约定。因此,您可以将其重命名为 useItemsState(我更喜欢 useItemsContext 以表明它只是一个专门针对您的特定上下文的 useContext 挂钩)。