如何使用 react-apollo 使用相同的查询进行多个 graphql 查询?

Posted

技术标签:

【中文标题】如何使用 react-apollo 使用相同的查询进行多个 graphql 查询?【英文标题】:How do I make mutliple graphql queries with the same query using react-apollo? 【发布时间】:2020-05-13 06:34:21 【问题描述】:

我有一个 graphql 端点:QueryDataForOptions

我想根据组件的options 属性多次调用它。 可能有任意数量的选项。

我想做这样的伪代码,但钩子的规则不允许这样做:

const MyComponent = (options) => 
  options.forEach(option => 
    const data, loading, error = useQuery(QueryDataForOptions, variables: option)
  )

我也考虑过这个伪代码,但我不确定如何处理 data 被覆盖:

const MyComponent = (options) => 
  const [getOptions, data, loading, error] = useLazyQuery(QueryDataForOptions)
  options.forEach(option => 
    getOptions(variables: option)
  )

我知道正确的解决方案是更改 graphql 端点,但我想在客户端进行此更改。

如何多次调用同一个查询?

【问题讨论】:

你能告诉我们QueryDataForOptions的样子吗? 它是虚构的,但看起来像:Query.dataForOptions( option: Int! )DataForOptions! 【参考方案1】:

Apollo 没有公开一个钩子来同时查询多个操作。但是,GraphQL 支持在每个操作中查询多个根字段。这一事实,再加上为字段设置别名的能力,意味着您可以在一个请求中获取所有需要的数据。

在编写查询时,您通常应该远离字符串插值,但在这种情况下,我们需要使用它。

const MyComponent = (options) => 
  const query = gql`
  query SomeNameForYourOperation (
    $options.map((option, index) => `$opt$index: SomeInputType!`).join('\n')
  )
    $options.map((option, index) => `
      alias$index: someRootField(someArgument: $opt$index) 
        ...SomeTypeFragment
      
    `).join('')
  

  fragment SomeTypeFragment on SomeType 
    someField
    someOtherField
  
  `

  const variables = options.reduce((memo, option, index) => 
    return  ...memo, [`opt$index`]: option 
  , )

  const  data, loading, error  = useQuery(query,  variables )

  if (data) 
    // data.alias0
    // data.alias1
    // etc.
    // You can also iterate through options again here and access the
    // appropriate alias by the index
  

这看起来有点复杂,但实际上非常简单。我们通过迭代options 来生成变量定义(我们最终得到$opt0$opt1 等变量)。然后我们再次遍历选项以生成根的选择集。对于每个选项,我们将相同的字段添加到我们的查询中,但我们将其别名(如alias0alias1 等),然后将不同的变量传递给该字段的参数。最后,我们利用片段来保持结果查询的大小可管理。

我们还必须将variables 对象传递给与我们生成的变量定义匹配的useQuery,因此我们将reduce options 数组放入具有适当命名属性的对象中。

当然,您需要更改上面的示例以包含特定于您的查询的类型、字段和参数。最终结果是您拥有一组 dataloadingerror 变量。查询加载后,您可以使用适当的别名(alias0 等)访问每个结果。

【讨论】:

Wish Apollo 提供了一种使这更容易的方法。无论如何,为什么还要使用variables,因为您已经在自己构建查询了。如果将变量放在查询本身中会不会更简单,对于服务器来说也可能更快。【参考方案2】:

您应该一次查询所有option,而不是查询每个option。因此,您的查询将采用我假设每个选项的 id 的数组,并返回一个数组,每个选项一个。如果您有 50 个选项,则一个查询将比尝试为每个选项触发一个查询要快得多且效果更好。

另一个不太可取的选项是为每个触发自己的查询的选项创建一个组件。 所以像

const MyComponent = (options) => (
  options.forEach(option => <OptionComponent option=option />)
)

const OptionComponent = ( option ) => 
  const [getOptions, data, loading, error] = useLazyQuery(QueryDataForOptions);

  if (loading) return 'Loading...';

  return (
    // whatever you want for each option
  );

【讨论】:

这需要更改后端。不幸的是,我无法控制它,所以我需要在前端解决这个问题。

以上是关于如何使用 react-apollo 使用相同的查询进行多个 graphql 查询?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 react-apollo graphql 查询中正确使用动态变量?

使用带有 react-apollo 查询的变量

将 Config.skip 与 React-Apollo 查询一起使用

React-Apollo,不要在组件加载时运行查询

如何在 react-apollo 中根据上下文使用两个不同的 websocket url?

React-Apollo:带变量的查询导致 UI 不再乐观