You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React Query数据无法同步到useReducer状态,值为undefined求助

React Query 结合 useReducer 时 state.clientList 为 undefined 的问题

我正在学习React Query,感觉自己漏掉了一些明显的点。以下是我的代码:

import {useReducer} from 'react'
import AppContext from './context'
import reducer from './reducer'
import apiClient from './http-commom'
import {useQuery} from 'react-query'

function App() {
  const getClientList = useQuery(
    ['client-list'],
    async ({signal}) => {
      return await apiClient.post('/v1/clientlist', {signal})
    },
    {enabled: true, refetchOnWindowFocus: false}
  )

  let clientList = getClientList?.data?.data?.recordset

  const initalState = {
    clientList: clientList,
  }

  const [state, dispatch] = useReducer(reducer, initalState)

  console.log(clientList) // 正常输出 ['client1','client2','client3']
  console.log(initalState.clientList) // 正常输出 ['client1','client2','client3']
  console.log(state.clientList) // 输出undefined

  return (
    <AppContext.Provider value={{state, dispatch}}>
      <div>testing</div>
    </AppContext.Provider>
  )
}

export default App

为何state中的值显示为undefined,但另外两个输出却正常?

我原本尝试在另一个组件中获取state.clientList,如下所示,之后将console.log移到App组件中以便对比:

function MenuBar() {
  const {state,dispatch} = useContext(AppContext)
  const {clientList} = state
  console.log(state.clientList) // undefined...
...

问题根源

useReducer的初始状态只会在组件第一次渲染时生效一次。React Query的useQuery是异步请求,组件首次渲染时请求还没完成,getClientList.data是undefined,所以clientList也是undefined,这时候useReducer就用这个undefined初始化了state。

等请求完成后组件重新渲染,虽然此时clientList和initalState.clientList都有值了,但useReducer不会再用新的初始状态去更新已有的state——它只认第一次初始化的那个值,所以state.clientList还是undefined。

解决方法

你需要在useQuery请求完成后,主动通过dispatch去更新reducer中的state,而不是依赖初始状态:

  1. 先给useReducer设置一个基础初始状态:
const initialState = {
  clientList: [], // 或者设为undefined,根据你的业务需求来
}

const [state, dispatch] = useReducer(reducer, initialState)
  1. 监听useQuery的数据变化,当数据返回时触发dispatch更新状态:
// 记得先导入useEffect
import {useReducer, useEffect} from 'react'

// ...

// 当useQuery成功获取数据后,更新state
useEffect(() => {
  if (getClientList.data) {
    const newClientList = getClientList.data.data.recordset
    dispatch({ type: 'SET_CLIENT_LIST', payload: newClientList })
  }
}, [getClientList.data, dispatch])
  1. 在你的reducer.js中添加对应的状态更新逻辑:
// reducer.js
export default function reducer(state, action) {
  switch (action.type) {
    case 'SET_CLIENT_LIST':
      return {
        ...state,
        clientList: action.payload
      }
    default:
      return state
  }
}

另外提个简化思路:如果你的clientList只需要通过React Query获取,没有其他复杂的状态修改逻辑,其实可以直接把useQuery的结果放到Context中,不需要额外用useReducer,这样能减少不必要的状态管理复杂度。


内容的提问来源于stack exchange,提问作者Lawrence Ferguson

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 14:05:30