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

bre*_*son 5 reactjs graphql react-apollo react-hooks

我有一个 graphql 端点:QueryDataForOptions

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

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

const MyComponent = (options) => {
  options.forEach(option => {
    const {data, loading, error} = useQuery(QueryDataForOptions, {variables: {option}})
  })
Run Code Online (Sandbox Code Playgroud)

}

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

const MyComponent = (options) => {
  const [getOptions, {data, loading, error}] = useLazyQuery(QueryDataForOptions)
  options.forEach(option => {
    getOptions({variables: {option}})
  })
}
Run Code Online (Sandbox Code Playgroud)

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

如何多次调用同一查询?

Dan*_*den 5

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
  }
}
Run Code Online (Sandbox Code Playgroud)

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

我们还必须传递一个与我们生成的变量定义相匹配的variables对象,因此我们将数组转换为具有适当命名属性的对象。useQueryreduceoptions

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

  • 希望阿波罗提供一种方法让这一切变得更容易。无论如何,为什么还要使用“变量”,因为您已经自己构建了查询。如果将变量放在查询本身中,不是会更简单,而且对于服务器来说也可能更快。 (2认同)

lar*_*arz 1

您应该一次查询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
  );
}
Run Code Online (Sandbox Code Playgroud)