7

我需要react-query库的帮助。我获取一个对象列表,然后为每个需要从另一个服务获取额外数据的人。我应该如何使用 react-queryuseQuery钩子来做到这一点?

示例 1

const { data} = useQuery("USERS", fetchUsers);
data.map(user => useQuery(["ACCOUNT", {userId: user.id}], 
                 ({userId}) => fetchAccount(userId)));

错误:

ESLint:useQuery不能在回调中调用 React Hook。React Hooks 必须在 React 函数组件或自定义 React Hook 函数中调用。(反应钩子/钩子规则)

4

5 回答 5

6

我找到了react-query作者提供的anwser:

根据您的描述,这似乎是经典的“我想在数组模式下使用 React 钩子”,我们以前肯定都遇到过。

99.9% 的情况下,我认为解决这个困境的方法是将钩子用法渲染到多个组件中并在渲染后组合它们的结果,但这里肯定存在边缘情况和大量权衡。但是,这是我们目前最好的解决方案,因为没有很好的方法来使用 MapHooks(item => useQuery(item), items)。那真的很棒,但相信我,我一直在走这条路,虽然我确实或多或少地得到了一些工作,但它最终使我的代码比我预期的复杂得多。目前,React Query 可能无法获得您正在谈论的功能,因为库本身使用钩子,它受到与您相同的机制的约束,并且需要大量的重新架构才能稍微接近您的内容'重新描述。

为了解决您今天的具体问题,我建议三种可能的解决方案:

  1. 即使您只需要一个,也可以请求多个列信息。调整您对这些列信息的记忆/使用,以仅在它们是新的时更新。这将使事情变得非常简单,并可能让您更快地前进。

  2. 将您的列信息提取器查询组合到不呈现任何内容的多个组件中,而是向它们传递一个道具,使它们能够将结果报告回父组件,然后将它们在父组件中的结果组合成单个列数组。

  3. 创建自己的小“缓存”来保存已获取的列信息列表,然后将获取逻辑组合到单个查询中。当数据可用时,使用您的自定义缓存对象填充该数组中的插槽,并通过尽可能频繁地清除缓存来保持最新状态。我认为这是最后的手段,因为您实际上将开始管理自己的自定义缓存,这正是 React Query 为您做的事情。如果你真的到了这里,我建议你在这里权衡一下使用 React Query 获得的好处。这可能是 React Query 的缓存/获取策略不适合的一种极端情况,这很好。

希望这可以帮助!

https://github.com/tannerlinsley/react-query/issues/138#issuecomment-589709270

于 2020-02-21T16:41:59.437 回答
5

使用依赖查询, -- 直到data(users) 被解析,然后你的第二个查询键字符串应该是虚假的,直到你有用户:

// rename `data` to `users`
const { data: users } = useQuery("USERS", fetchUsers);

// `users` causes query key to be falsy until they are loaded
// rename `data` to `accounts`, map `users` id only and pass to pass in as param
const { data: accounts } = useQuery([users && "ACCOUNT", users.map((u) => u.id)], async (key, userIds) => {
  const response = await fetchAccounts(userIds);

  // TODO any mapping?

  return response;
});

https://www.npmjs.com/package/react-query#dependent-queries

于 2020-05-22T22:21:11.453 回答
4

这看起来至少是 react-query v3 的当前解决方案:

 // Get the user
 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,
   }
 )

 // isIdle will be `true` until `enabled` is true and the query begins to fetch.
 // It will then go to the `isLoading` stage and hopefully the `isSuccess` stage :)

依赖查询文档

于 2021-02-17T16:51:50.153 回答
0

我已经开始为此使用另一种技术,我从“get”函数进行两次调用。优点是隐藏了函数背后的 API 复杂性。缺点是对组件的粒度控制较少。

下面是一个类似于我通常做的例子(未经测试)。

 const getProjectsByUser = () => {
   // I'm using axios, but you can use fetch or something else.
   const {data} = axios.get("/api/user")
   
   // Let's assume the user endpoint returns a user with an array of projects
   const projectNames = data.user.projects

   const fetchProjects = projecNames.map(name => axios.get(`/api/projects/${name}`)
   
   // I may use Promise.all or Promise.allSettled
   const projResponses = await Promise.all(fetchProjects)

   return projResponses.data;
 }

某些组件上的唯一代码:

 import {getProjectsByUser } from "some path"

 const { data: user } = useQuery(['user', email], getProjectsByUser)
 const userId = user?.id
 
于 2021-07-14T08:49:25.540 回答
0

在反应查询的文档中,您可以找到并行查询,它解释了您的问题,如果您需要两个数据,您可以执行以下操作

const { data} = useQuery("USERS", fetchUsers);
const {data:fetchAccount} = useQuery('Account , {userId: user.id}] ,fetchAccount))) 

fetchAccount.map((item)=>{
return (
<div key={item.id}>{item.stuffs}</div>
)
}
于 2021-11-28T08:27:48.657 回答