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,而不是依赖初始状态:
- 先给
useReducer设置一个基础初始状态:
const initialState = { clientList: [], // 或者设为undefined,根据你的业务需求来 } const [state, dispatch] = useReducer(reducer, initialState)
- 监听
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])
- 在你的
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
相关产品推荐
相关产品推荐

