我有一个 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 端点,但我想在客户端进行此更改。
如何对同一查询进行多次调用?
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
等变量(。然后,我们再次循环访问这些选项,为根生成选择集。对于每个选项,我们将相同的字段添加到查询中,但我们将其别名化(如alias0
、alias1
等(,然后将不同的变量传递给字段的参数。最后,我们利用片段来保持生成的查询的大小可管理。
我们还必须将一个variables
对象传递给与我们生成的变量定义匹配的useQuery
,因此我们将options
数组reduce
到具有适当命名属性的对象中。
当然,您需要更改上面的示例以包含特定于查询的类型、字段和参数。最终结果是你只有一组data
、loading
和error
变量。加载查询后,可以在适当的别名(alias0
等(下访问每个结果。
与其对每个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
);
}