Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Is there a way to use the Query component like Promise.all? #3433

Closed
ollie-o opened this issue May 9, 2018 · 6 comments
Closed

Is there a way to use the Query component like Promise.all? #3433

ollie-o opened this issue May 9, 2018 · 6 comments

Comments

@ollie-o
Copy link

ollie-o commented May 9, 2018

Intended outcome:

I have a React component that needs 7 GraphQL queries to finish firing before I can render the page. I need an error state, a loading state, and of course a final state generated by combining responses from all of the queries.

I want to do this concisely and cleanly.

I would like to do something similar to the behavior in Promise.all():

const queryOne = this._apolloClient.query(optionsOne);
const queryTwo = this._apolloClient.query(optionsTwo);
const queryThree = this._apolloClient.query(optionsThree);
const queryFour = this._apolloClient.query(optionsFour);

// Like Promise.all([queryOne, queryTwo, queryThree, queryFour]);

<Query queryArray=[queryOne, queryTwo, queryThree, queryFour]>
    {({ loading, error, data }) => {
        // data --> [dataOne, dataTwo, dataThree, dataFour]
        // loading --> true if any of these are still loading
        // error --> [error1, errorTwo, errorThree, errorFour]
    }}
</Query>

How can I achieve this? I could definitely roll my own fairly easily but if there is a built-in way to achieve this I would love to use it.

Actual outcome:

The best solution I can come up with is something like:

<Query>
  <Query>
    <Query>
      <Query>
        { // etc. }
      </Query>
    </Query>
  </Query>
</Query>

But that is:

  • Executed in order (not parallel like Promise.all)
  • Very ugly syntax after you add in all the details

How to reproduce the issue:

Not applicable.

Version

  • apollo-client@<2.1.4>
@TimMikeladze
Copy link
Contributor

Have you considered putting all your queries into a single query document?

Foo.graphql

query Foo {
  queryOne { ... }
  queryTwo { ... }
  queryThree { ... }
}

Then you can use a single Query component passing it Foo for the query prop.

Alternatively you can achieve similar behavior with 7 queries using the graphql higher order component.

@ollie-o
Copy link
Author

ollie-o commented May 10, 2018

Thank you for the quick response!

Alternatively you can achieve similar behavior with 7 queries using the graphql higher order component.

That's how we currently have our code. It works, but ideally we'd love to use something like the <Query> component because that style is so readable compared to the HOC.

The other benefit I'm trying to achieve is for the requests to be sent in parallel.

Have you considered putting all your queries into a single query document?

I looked into that, but I had trouble because 6 of the queries are the same query, just with different variables (I know it sounds weird, but it makes sense for our project). I couldn't figure out how to ensure that the variable names didn't collide when the identically-named queries were returned.

Another downside I can see is less useful caching. It's more useful to me to separately cache each of the requests since there can be many combinations of them.


Thanks for your help! Looks like I'll end up making my own <QueryAll> component locally. It's good to get confirmation that I'm not creating something that already exists 👍

@mjlaufer
Copy link

@oliverodaa Have you given this a try? https://github.com/jamesplease/react-composer

@ollie-o
Copy link
Author

ollie-o commented May 15, 2018

I ended up doing as @TimMikeladze recommended.

I put all the queries into one long query document and it worked very nicely.

I used aliases to deal with the fact that some of the queries were the same, just with different variables.

Because of server-side caching, I realized my caching concerns were not a big deal.

Hopefully this thread helps someone in future!

@ollie-o ollie-o closed this as completed May 15, 2018
@margalit
Copy link

For any one else who ends up trying to do something similar—you can always create custom query functionality by directly calling the client.query function that returns a promise. You can access the client object through render props via the ApolloProvider or component props the withApollo higher order function.

eg:

export default withApollo(MyComponent);

function MyComponent({ client }) {
  console.log(client.query({
    query: GET_DOG_PHOTO,
    variables: { breed: "bulldog" }
  }));
  // Promise {<pending>}
}

@lizongze
Copy link

lizongze commented Sep 26, 2018

@TimMikeladze but how to pass different query params to each one query ?

query Foo {
  queryOne { ... }
  queryTwo { ... }
  queryThree { ... }
}
graphql<IProps, Query>(Foo, {
  options: ({ queryParams }) => ({
    fetchPolicy: 'network-only',
    variables: {
      params: queryParams,
    },
  }),
})(Comp);

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants