如何使用React-Query处理多个查询



我已经开始使用React-Query,如果我只需要从数据库中的单个集合中获取数据,它就可以很好地工作。然而,我正在努力寻找一种好方法来查询多个集合,以便在单个组件中使用。

一个查询(没有问题):

const { isLoading, isError, data, error } = useQuery('stuff', fetchStuff)
if (isLoading) {
return <span>Loading...</span>
}

if (isError) {
return <span>Error: {error.message}</span>
}

return (
<ul>
{data.map(stuff => (
<li key={stuff.id}>{stuff.title}</li>
))}
</ul>
)
}

对不同集合的多个查询(😬):

const { isLoading: isLoadingStuff, isError: isErrorStuff, data: stuff, error: errorStuff } = useQuery('stuff', fetchStuff);
const { isLoading: isLoadingThings, isError: isErrorThings, data: Things, error: errorThings } = useQuery('things', fetchThings);
const { isLoading: isLoadingDifferentStuff, isError: isErrorDifferentStuff, data: DifferentStuff, error: errorDifferentStuff } = useQuery('DifferentStuff', fetchDifferentStuff);
const isLoading = isLoadingStuff || isLoadingThings || isLoadingDifferentStuff
const isError = isErrorStuff || isErrorThings || isErrorDifferentStuff
const error = [errorStuff, errorThings, errorDifferentStuff]
if (isLoading) {
return <span>Loading...</span>
}

if (isError) {
return (
<span>
{error.forEach((e) => (e ? console.log(e) : null))}
Error: see console!
</span>
);
}

return (
<>
<ul>
{stuff.map((el) => (
<li key={el.id}>{el.title}</li>
))}
</ul>
<ul>
{things.map((el) => (
<li key={el.id}>{el.title}</li>
))}
</ul>
<ul>
{differentStuff.map((el) => (
<li key={el.id}>{el.title}</li>
))}
</ul>
</>
);
}

我相信一定有更好的方法来做这件事。出于多种原因,我对React-Query非常感兴趣,但其中一个好处是减少了样板文件。然而,这种方法似乎并不比使用useEffect和useState来管理我的api调用好多少。我确实找到了useQueries钩子,但它并没有使它变得更干净。

有没有人知道,如果有一个方法在React-Query使多个查询,只得到一个isLoading, isError,和错误(数组?)响应?或者只是一种更好的方式来处理我错过的多个查询?

我确实找到了useQueries钩子,但它并没有使它变得更干净。

useQueries为您提供了一个结果数组,因此您可以对它们进行映射:

const isLoading = queryResults.some(query => query.isLoading)

如果您有一个触发多个并发请求的组件,那么库可以做的只有这么多来降低复杂性。每个查询都可以有自己的加载状态/错误状态/数据。每个查询都可以有自己的设置,行为也不同。推荐的方法仍然是将其提取到自定义钩子中,并从中返回您想要的内容。

通过使用useErrorBoundary

选项的错误边界可以简化错误处理。为了简化加载体验,您可以尝试suspense(虽然是实验性的),它将为所有查询显示fallback加载器。

这种方法似乎并不比使用useEffect和useState来管理我的api调用好多少。

这忽略了所有的优点,比如缓存、后台重取、突变、智能失效等。

使用依赖查询,您可以遵循文档中的示例。

const { data: user } = useQuery(['user', email], getUserByEmail)
const userId = user?.id
// Then get the user's projects
const { isIdle, data: projects } = useQuery(
['projects', userId],
getProjectsByUser,
{
// The query will not execute until the userId exists
enabled: !!userId,
}
)

官方文档-依赖查询

有两个选项:

  • 如果查询是相互独立的,可以使用useQueries钩子。
import React from 'react';
import { useQueries } from '@tanstack/react-query';
import axios from 'axios';
export default function Example() {
const [postsQuery, usersQuery] = useQueries({
queries: [
{
queryKey: ['posts'],
queryFn: () =>
axios
.get('https://jsonplaceholder.typicode.com/posts')
.then((res) => res.data),
},
{
queryKey: ['users'],
queryFn: () =>
axios
.get('https://jsonplaceholder.typicode.com/users')
.then((res) => res.data),
},
],
});
if (postsQuery.isLoading) return 'Loading Posts...';
if (usersQuery.isLoading) return 'Loading Users...';
if (postsQuery.error)
return 'An error has occurred: ' + postsQuery.error.message;
if (usersQuery.error)
return 'An error has occurred: ' + usersQuery.error.message;
return (
<div>
<h2>Posts</h2>
{postsQuery.data?.map((post) => {
return (
<div key={post.id} style={{ display: 'flex' }}>
<span>{post.id}-&nbsp;</span>
<div>{post.title}</div>
</div>
);
})}
<h2>Users</h2>
{usersQuery.data?.map((user) => {
return (
<div key={user.id} style={{ display: 'flex' }}>
<span>{user.id}-&nbsp;</span>
<div>{user.name}</div>
</div>
);
})}
</div>
);
}
  • OR,使用依赖查询选项,通过添加enabled属性。
import React from 'react';
import { useQuery } from '@tanstack/react-query';
import axios from 'axios';
export default function Example() {
const {
isLoading: loadingPost,
error: errorPost,
data: postData,
} = useQuery(['post', 1], () =>
axios
.get('https://jsonplaceholder.typicode.com/posts/1')
.then((res) => res.data)
);
const {
isLoading: loadingPostComments,
error: errorPostComments,
data: commentsData,
} = useQuery(
['comments', 'post', 1],
() =>
axios
.get('https://jsonplaceholder.typicode.com/posts/1/comments')
.then((res) => res.data),
{
enabled: postData && Object.keys(postData).length > 0,
}
);
if (loadingPost) return 'Loading Posts...';
if (errorPost) return 'An error has occurred: ' + errorPost.message;
if (loadingPostComments) return 'Loading Comments...';
if (errorPostComments)
return 'An error has occurred: ' + errorPostComments.message;
return (
<div>
<h2>Post</h2>
{postData && (
<div key={postData.id} style={{ display: 'flex' }}>
<span>{postData.id}-&nbsp;</span>
<div>{postData.title}</div>
</div>
)}
<h2>-- Comments</h2>
{commentsData?.map((comment) => {
return (
<div key={comment.id} style={{ display: 'flex' }}>
<span>{comment.id}-&nbsp;</span>
<div>{comment.body}</div>
</div>
);
})}
</div>
);
}

你可以在这个链接上找到更多信息。

您可以将您的查询抽象到单个查询文件中,然后为您想要一起获取的每个数据集合(最有可能的是,呈现单个页面所需的查询集合)创建自定义钩子

// ../queries/someQuery.js
export const useContactInformation = () => {
const { data, isLoading, error } = useQuery(CONTACT_INFORMATION, () => apicall(someparams), {
enabled: !!user?.id,
});
return {
contactInformation: data
isLoading,
error,
};
};

,然后在另一个文件…

// ../hooks/somepage.js
export const useSomePageData = () => {
const { contactInformation, error: contactError, isLoading: contactIsLoading } = useContactInformation();
const { activityList, error: activityError, completedActivity, isLoading: activityIsLoading } = useActivityList();
# return true, only when all queries are done
const isLoading = activityIsLoading || contactIsLoading;
# return true, only when all queries run successfully
const error = activityError || contactError;
return {
error,
isLoading,
activityList,
};
};

最新更新