编者注:==本文介绍了一种使用模式匹配优雅处理TanStack React Query各种状态(加载中、错误、成功、空数据)的方法==。1) 通过matchQueryStatus工具函数将复杂的状态判断逻辑封装起来;2) 使组件代码更简洁、类型更安全;3) 遵循"沙漏模式"将复杂状态映射简化为两步处理。这种方法特别适合需要频繁处理异步状态的React应用。**
使用模式匹配简化TanStack React Query状态处理
==简单解决方案往往能产生重大影响==。在React巴黎大会上,我遇到一位React开发者说:"我记得你在LinkedIn上发过一篇关于React Query的帖子,现在我的同事都在用这个技巧。"我花了一些时间找到了这篇帖子,现在似乎是写博客详细说明的好时机。
回到正题:==异步数据获取是许多Web应用的核心部分==。TanStack React Query是管理服务器状态的优秀库。然而,根据查询状态(加载中、错误、成功、可能为空)渲染不同UI有时会导致组件内出现冗长繁琐的条件逻辑。
本文灵感来自Dominik Dorfmeister的文章《组合确实很棒》。
挑战:处理多种查询状态
通常,使用useQuery时代码可能如下:
import { usePostsListQuery } from "./posts/queries";
export default function PostLists() {
const postsQuery = usePostsListQuery();
if (postsQuery.isLoading) {
return <LoadingSpinner />;
}
if (postsQuery.isError) {
return (
<ErrorMessage error={postsQuery.error} refetch={postsQuery.refetch} />
);
}
if (!postsQuery.data || postsQuery.data.length === 0) {
return <EmptyMessage message="No posts found." />;
}
// 成功状态
return (
<ul>
{postsQuery.data.map((post) => (
<li key={post.id}>{post.title}</li>
))}
</ul>
);
}
虽然可行,但随着组件增长或需要在应用中重复处理这些状态时,嵌套的if语句或多个三元表达式会变得笨拙。
更简洁的方法:模式匹配工具
示例
我们的组件可以这样写:
import { usePostsListQuery } from "./posts/queries";
import { matchQueryStatus } from "./utils/matchQueryStatus";
import PostsListLayout from "./components/PostsListLayout";
export default function PostsList() {
const postsQuery = usePostsListQuery();
return (
<PostsListLayout>
{matchQueryStatus(postsQuery, {
Loading: <LoadingSpinner />
Errored: (error) => <ErrorMessage error={error.message} />,
Empty: <EmptyMessage message="No posts found." />,
Success: ({ data }) => (
<ul>
{data.map((post) => (
<li key={post.id}>{post.title}</li>
))}
</ul>
)
})}
</PostsListLayout>
);
}
很优雅,不是吗?所有复杂条件逻辑都消失了!
实现原理
这个工具函数将查询结果对象和状态映射选项对象作为参数:
import { type UseQueryResult } from "@tanstack/react-query";
export function matchQueryStatus<T>(
query: UseQueryResult<T>,
{
Loading,
Errored,
Empty,
Success,
}: {
Loading: JSX.Element;
Errored: JSX.Element | ((error: unknown) => JSX.Element);
Empty?: JSX.Element;
Success: (data: UseQueryResult<T>) => JSX.Element;
}
): JSX.Element {
if (query.isLoading) {
return Loading;
}
if (query.isError) {
if (typeof Errored === "function") {
return Errored(query.error);
}
return Errored;
}
const isEmpty =
query.data === undefined ||
query.data === null ||
(Array.isArray(query.data) && query.data.length === 0);
if (isEmpty && Empty) {
return Empty;
}
return Success(query);
}
结论
使用matchQueryStatus模式匹配工具处理TanStack React Query结果有多个优点:
- ==可读性==:将状态处理逻辑整合为单一声明式结构
- ==可维护性==:更容易修改或添加特定状态处理
- ==可重用性==:可在不同组件中复用
- ==类型安全==:利用TypeScript提供更好的类型保证
代码可在Gist获取。
译者:Claude 3.5 Sonnet