简体   繁体   中英

How do I make mutliple graphql queries with the same query using react-apollo?

I have a graphql endpoint: QueryDataForOptions

I want to call it multiple times based on the component's options prop. There may be any number of options.

I would like to do something like this pseudocode but the rules of hooks do not allow it:

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

}

I also considered this pseudocode but I am not sure how to handle data being overwritten:

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

I know the right solution is to change the graphql endpoint but I want to do this change on the client side.

How do I make multiple calls of the same query?

Apollo does not expose a hook to query multiple operations simultaneously. However, GraphQL supports querying multiple root fields per operation. This fact, combined with the ability to alias fields, means you can get all your required data in a single request.

You should normally stay away from string interpolation when composing queries, but in this case we'll need to use it.

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
  }
}

This looks a bit complicated but it's actually pretty straightforward. We generate the variable definitions by iterating through the options (we end up with variables like $opt0 , $opt1 , etc.). We then iterate through the options again to generate the selection set for the root. For each option, we add the same field to our query, but we alias it (as alias0 , alias1 , etc.) and then pass a different variable to the argument for the field. Lastly, we utilize a fragment to keep the size of the resulting query manageable.

We also have to pass a variables object to useQuery that matches the variable definitions we generated, so we reduce the options array into an object with appropriately named properties.

Of course, you'll need to change the above example to include the types, fields and arguments specific to your query. The end result is that you have a single set of data , loading and error variables. Once the query loads, you can access each result under the appropriate alias ( alias0 , etc.).

Instead of making a query for each option , you should query for all of them at once. So your query will take an array of what I assume will be ids for each option, and return back an array, one for each option. If you have 50 options, one query will be strikingly faster and better than trying to fire off one query for each option.

Another, less preferable option is to create a component for each option which fires off its own query. So something like

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
  );
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM