React Query获取API数据返回undefined问题求助
问题:React Query useQuery返回data始终为undefined
相关代码
自定义API调用中间件apiCaller:
/* eslint-disable @typescript-eslint/no-var-requires */ // /* eslint-disable no-import-assign */ import Axios from 'axios'; import * as queryString from 'query-string'; const caseConverter = require('change-object-case'); import { cleanParams } from '_utilities/common'; import { REQUEST_TYPES } from './constants'; import { useLoginUser } from '_store/user'; interface IAuth { method?: string; url?: string; data?: any; params?:any, contentType?:string, isTransformRequestRequired?:boolean } export function apiCaller( { method = REQUEST_TYPES.GET, url = '', params = {}, data = {}, contentType = 'application/json', isTransformRequestRequired = true, }:IAuth, ) { const user = useLoginUser.getState().user; const token = user?.data?.token || ''; // caseConverter.options = {recursive: true, arrayRecursive: true}; return Axios({ method, url, params, paramsSerializer: queryParams => queryString.stringify(caseConverter.snakeKeys(cleanParams(queryParams))), data, transformRequest: [reqData => isTransformRequestRequired ? JSON.stringify(caseConverter.toSnake(reqData)) : reqData], transformResponse: [(respData) => { if(typeof respData === 'string') return JSON.parse(respData) else { return respData } }], headers: { Authorization: user !== null ? `Token ${ token }` : '', 'Content-Type': contentType, }, responseType: 'json', validateStatus: status => status >= 200 && status < 300, }) .then(({ data: resp }) => resp) .catch(error => { console.log(error,'error') // if user session is expired from server and got 401, will logout the user from application if(error.response.status === 401) { // store.dispatch(logoutSuccess()); } else { throw(error); } }); }
调用apiCaller的usersApi:
import { apiCaller } from '../api-caller'; import { ENDPOINTS, REQUEST_TYPES } from '../constants'; import moment from 'moment'; export const usersApi = async (params:any) => { const res = await apiCaller( { method: REQUEST_TYPES.GET, url: `${ENDPOINTS.USERS}/`, params:{ ...params, startDatetime: params.startDatetime ? moment(params.startDatetime).utc().format('YYYY-MM-DD H:mm:ss') : '', endDatetime: params.endDatetime ? moment(params.endDatetime).utc().format('YYYY-MM-DD H:mm:ss') : '', }, }, ); return res; }
封装useQuery的useCreateProfile Hook:
import { useQuery } from '@tanstack/react-query' import { usersApi } from '_api/users' import { useAdminUser } from 'pages/Admin/AdminUsers/_store' const filters = useAdminUser.getState().filters export const useCreateProfile = () => { const query = ['cashierShifts'] return useQuery(query, () => { usersApi(filters) }) }
组件中使用Hook:
import React, { useState } from 'react' import { Table } from 'antd' import { useCreateProfile } from '_services/CashierProfile' const columns = [ { title: 'Day', dataIndex: 'day', key: 'day', }, { title: 'Shift', dataIndex: 'shift', key: 'shift', }, { title: 'startTime', dataIndex: 'start', key: 'start', }, { title: 'endTime', dataIndex: 'end', key: 'end', }, { title: 'Mart', dataIndex: 'mart', key: 'mart', }, ] const CashierShifts = () => { const { data, isError, isLoading, isSuccess } = useCreateProfile() console.log(data, 'react-query') const [result, setResult] = useState([ { id: 54, tile: 'slots 1', date: '22-10-2203', startTime: '8:00', mart: { id: 21, martName: 'Johar Town', }, endTime: '12:00', cashier: { name: 'Jamal', id: 54, }, }, { id: 54, tile: 'slots 1', date: '22-10-2203', startTime: '8:00', mart: { id: 21, martName: 'Johar Town', }, endTime: '12:00', cashier: { name: 'Jamal', id: 54, }, }, { id: 54, tile: 'slots 1', date: '22-10-2203', startTime: '8:00', mart: { id: 21, martName: 'Johar Town', }, endTime: '12:00', cashier: { name: 'Jamal', id: 54, }, }, { id: 54, tile: 'slots 1', date: '22-10-2203', startTime: '8:00', mart: { id: 21, martName: 'Johar Town', }, endTime: '12:00', cashier: { name: 'Jamal', id: 54, }, }, ]) const dataSource = result.map((a) => ({ day: a.date, shift: a.tile, start: a.startTime, end: a.endTime, mart: a.mart.martName, })) return ( <div> <Table columns={columns} dataSource={dataSource} /> </div> ) } export default CashierShifts
问题排查与修复
核心原因1:useQuery查询函数未返回Promise
在useCreateProfile中,useQuery的第二个箭头函数调用usersApi(filters)后未返回该Promise,导致React Query无法捕获异步请求结果,最终data始终为undefined。
核心原因2:filters获取时机错误
在Hook外部直接读取filters,只会在Hook初始化时获取一次值,后续store中filters变化时不会触发useQuery重新查询,还可能传递未初始化的参数给接口。
修复方案
修改useCreateProfile Hook,确保返回Promise并正确处理依赖参数:
import { useQuery } from '@tanstack/react-query' import { usersApi } from '_api/users' import { useAdminUser } from 'pages/Admin/AdminUsers/_store' export const useCreateProfile = () => { // 在Hook内部获取最新的filters const filters = useAdminUser.getState().filters // 将filters加入queryKey,参数变化时自动触发重新查询 const queryKey = ['cashierShifts', filters] return useQuery(queryKey, () => { // 返回usersApi的Promise,让React Query处理异步结果 return usersApi(filters) }) }
额外优化:添加错误处理
在组件中添加错误状态捕获,方便排查请求失败的情况:
const CashierShifts = () => { const { data, isError, isLoading, isSuccess, error } = useCreateProfile() // 打印错误信息辅助排查 if (isError) { console.error('请求失败:', error) } console.log(data, 'react-query') // ... 其他组件代码 }
验证要点
- 单独调用
usersApi确认能正常返回后端数据 - 检查浏览器Network面板,确认接口请求是否成功、响应数据是否正确
- 确保React Query的Provider已正确包裹应用根组件
内容的提问来源于stack exchange,提问作者Asad Ur Rehman
相关产品推荐
相关产品推荐

