繁体   English   中英

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

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

在调试itemsstate时,由于加载,它们最初是空的,但是只有items接收到正确的数据,而 state 仍然是空数组。

如果我将 static 数据放入let items ,它就可以正常工作,所以我的useQuery也可能有问题吗?

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

要解决这个问题,您需要接受 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导出似乎是一个自定义挂钩(它不能是其他任何东西,因为它不是一个组件而是使用一个挂钩) - 这很好但是有是 React 中一个非常严格的约定,所有自定义钩子的名称都采用useXXX形式,我强烈建议您遵循该约定。 因此,您可以将其重命名为useItemsState (我更喜欢useItemsContext以明确它只是一个专门针对您的特定上下文的useContext挂钩)。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM