1
votes

The setup:

My basic setup is a Next.js app querying data from a GraphQL API.

I am fetching an array of objects from the API and am able to display that array on the client.

I want to be able to filter the data based on Enum values that are defined in the API schema. I am able to pass these values programmatically and the data is correctly updated.

I want those filters to be persistent when a user leaves the page & come back. I was originally planning to use Redux, but then I read about apollo-link-state and the ability to store local (client) state into the Apollo store, so I set out to use that instead. So far, so good.

The problem:

When I try to combine the local query and the remote query into a single one, I get the following error: networkError: TypeError: Cannot read property 'some' of undefined

My query looks like this:

const GET_COMBINED = gql`
  {
    items {
      id
      details
    }
    filters @client
  }
`

And I use it inside a component like this:

export default const Items = () => (
  <Query query={GET_COMBINED}>
    {({ loading, error, data: { items, filters } }) => {
      ...do stuff...
    }}
  </Query>
)

IF however, I run the queries separately, like the following:

const GET_ITEMS = gql`
  {
    items {
      id
      details
    }
  }
`
const GET_FILTERS = gql`
  {
    filters @client
  }
`

And nest the queries inside the component:

export default const Items = () => (
  <Query query={GET_ITEMS}>
    {({ loading, error, data: { items } }) => {
      return (
        <Query query={GET_FILTERS}>
          {({ data: { filters } }) => {
            ...do stuff...
          }}
        </Query>
      )
    }}
  </Query>
)

Then it works as intended!

But it seems far from optimal to nest queries like this when a single query would - in theory, at least - do the job. And I truly don't understand why the combined query won't work.

I've stripped my app to its bare bones trying to understand, but the gist of it is, whenever I try to combine fetching local & remote data into a single query, it fails miserably, while in isolation both work just fine.

Is the problem coming from SSR/Next? Am I doing it wrong? Thanks in advance for your help!

Edit 2 - additional details

The error is triggered by react-apollo's getDataFromTree, however even when I choose to skip the query during SSR (by passing the ssr: false prop to the Query component), the combined query still fails. Besides, both the remote AND local queries work server-side when run separately. I am puzzled.

I've put together a small repo based on NextJS's with-apollo example that reproduces the problem here: https://github.com/jaxxeh/next-with-apollo-local

Once the app is running, clicking on the Posts (combined) link straight away will trigger an error, while Posts (split) link will display the data as intended.

Once the data has been loaded, the Posts (combined) will show data, but the attempt to load extra data will trigger an error. Reloading (i.e. server-rendering) the page will also trigger an error. Checkboxes will be functional and their state preserved across the app.

The Posts (split) page will fully function as intended. You can load extra post data, reload the page and set checkboxes.

So there is clearly an issue with the combined query, be it on the server-side (error on reload) or the client-side (unable to display additional posts). Direct writes to the local state (which bypass the query altogether) do work, however.

I've removed the Apollo init code for brevity & clarity, it is available on the repo linked above. Thank you.

1
Please include your Apollo client config, at least the bits relevant to apollo-link-state like defaults, resolvers, etc.Daniel Rearden
@DanielRearden I've added the Apollo client init code. Thank you.Thomas Hennes
Also, there is no resolver because there is no need for one. The entire array is overwritten depending on the state of 4 checkboxes, and the checkboxes are initially set according to the values contained in the array.Thomas Hennes
@DanielRearden edited the question with the repo of a fully working example of the errorThomas Hennes
I can't reproduce the error above, but I did see Cannot read property 'Query' of undefined getting thrown. Adding a resolvers map fixed the error and I was able to render both components just fine.Daniel Rearden

1 Answers

1
votes

Add an empty object as your resolver map to the config you pass to withClientState:

const stateLink = withClientState({
  cache,
  defaults: {
    filters: ['A', 'B', 'C', 'D']
  },
  resolvers: {},
  typedefs: `
    type Query {
      filters: [String!]!
    }
  `,
})

There's a related issue here. Would be great if the constructor threw some kind of error if the option was missing or if the docs were clearer about it.