React Query重复处理isLoading/error的替代方案咨询
解决React Query重复状态判断的几种方案
1. 封装通用状态处理组件
把loading、error、空数据的UI逻辑抽成可复用组件,业务组件只需传入查询结果和正常渲染内容:
// QueryStatusWrapper.jsx import React from 'react'; export function QueryStatusWrapper({ queryResult, emptyText = '暂无数据', loadingText = '加载中...', errorText = '加载失败', children }) { if (queryResult.isLoading) { return <div>{loadingText}</div>; } if (queryResult.isError) { return <div>{errorText}</div>; } if (!queryResult.data) { return <div>{emptyText}</div>; } return children; }
业务组件使用示例:
import { useQuery } from "@tanstack/react-query"; import { fetchAllUsers } from "./useFetchUsers"; import { QueryStatusWrapper } from './QueryStatusWrapper'; const TestComponent = () => { const queryResult = useQuery({ queryKey: ["Users"], queryFn: fetchAllUsers, }); return ( <QueryStatusWrapper queryResult={queryResult}> <div>{queryResult.data}</div> </QueryStatusWrapper> ); }; export default TestComponent;
后续要统一修改loading样式、文案时,直接改Wrapper组件即可,不用逐个业务组件调整。
2. 封装自定义Hook
把useQuery调用和状态判断逻辑封装成自定义Hook,返回处理后的状态字段,简化业务组件代码:
// useCustomQuery.js import { useQuery } from "@tanstack/react-query"; export function useCustomQuery(options) { const queryResult = useQuery(options); return { ...queryResult, // 新增isEmpty字段,避免重复判断!data isEmpty: !queryResult.isLoading && !queryResult.isError && !queryResult.data, }; }
业务组件使用示例:
import { useCustomQuery } from "./useCustomQuery"; import { fetchAllUsers } from "./useFetchUsers"; const TestComponent = () => { const { data, isLoading, isError, isEmpty } = useCustomQuery({ queryKey: ["Users"], queryFn: fetchAllUsers, }); if (isLoading) return <div>加载中...</div>; if (isError) return <div>加载失败</div>; if (isEmpty) return <div>暂无数据</div>; return <div>{data}</div>; };
3. 利用React Query内置状态解构
React Query本身提供了isLoading、isError、isSuccess等组合状态,直接解构这些字段能大幅简化代码:
import { useQuery } from "@tanstack/react-query"; import { fetchAllUsers } from "./useFetchUsers"; const TestComponent = () => { const { isLoading, isError, data } = useQuery({ queryKey: ["Users"], queryFn: fetchAllUsers, }); if (isLoading) return <div>加载中...</div>; if (isError) return <div>加载失败</div>; if (!data) return <div>暂无数据</div>; return <div>{data}</div>; };
相比原写法,解构后代码更简洁,可读性也更高。
4. 结合Suspense与Error Boundary(React 18+)
如果使用React 18+,可以开启React Query的suspense: true,配合Suspense组件和Error Boundary集中处理加载、错误状态,业务组件无需写状态判断:
首先在全局配置开启suspense:
// App.jsx import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { Suspense } from 'react'; import ErrorBoundary from './ErrorBoundary'; import TestComponent from './TestComponent'; const queryClient = new QueryClient({ defaultOptions: { queries: { suspense: true, }, }, }); function App() { return ( <QueryClientProvider client={queryClient}> <ErrorBoundary fallback={<div>加载失败</div>}> <Suspense fallback={<div>加载中...</div>}> <TestComponent /> </Suspense> </ErrorBoundary> </QueryClientProvider> ); }
业务组件直接使用数据:
import { useQuery } from "@tanstack/react-query"; import { fetchAllUsers } from "./useFetchUsers"; const TestComponent = () => { const { data } = useQuery({ queryKey: ["Users"], queryFn: fetchAllUsers, }); // 空数据可在fetch函数返回默认值(比如空数组),避免此处判断 if (!data) return <div>暂无数据</div>; return <div>{data}</div>; };
该方案将状态处理集中在顶层,业务组件只关注正常渲染逻辑,但需要额外实现Error Boundary组件。
内容的提问来源于stack exchange,提问作者Zach philipp
相关产品推荐
相关产品推荐

