2
votes

I'm trying to implement a CRUD application using Apollo Client using nextJS and the serverless Framework as GraphQL backend. Is there any way to prevent unnecessary automatic refetch during app navigation using the cache?

For instance, I'm creating a new record with a mutation, adding refetchQueries will refresh the cache, but assuming the user is navigating to another view and then coming back to the view using useQuery hook, the data will be fetched again, but it's supposed being already in the cache.

Here's my ApolloClient configuration:

import {ApolloClient} from 'apollo-client'
import {InMemoryCache, NormalizedCacheObject} from 'apollo-cache-inmemory'
import {createHttpLink, HttpLink} from 'apollo-link-http'

import {default as fetch} from 'isomorphic-unfetch'
import {config} from '~config'
const {IS_SERVER} = config

import {getToken} from '~security'
const token = getToken()
import {setContext} from 'apollo-link-context'

const authLink = setContext((_, {headers}) => {
    return {
      headers: {
        ...headers,
        Authorization: token && `Bearer ${token}`,
      }
    }
})

const httpLink = createHttpLink({
    uri: 'http://localhost:4000/graphql',
    fetch
})

let apolloClient: ApolloClient<NormalizedCacheObject> | null = null
const create = (initialState = {}): ApolloClient<NormalizedCacheObject> => {
  const httpLinkConfig: HttpLink.Options = {
    uri: 'http://localhost:4000/graphql',
    credentials: 'same-origin'
  }
  if (!IS_SERVER) {
    httpLinkConfig.fetch = fetch;
  }
  return new ApolloClient({
    connectToDevTools: !IS_SERVER,
    ssrMode: IS_SERVER,
    link: authLink.concat(httpLink),
    cache: new InMemoryCache().restore(initialState)
  })
}

export const initApollo = (initialState = {}): ApolloClient<NormalizedCacheObject> => {
  if (!IS_SERVER) {
    return create(initialState)
  }
  if (!apolloClient) {
    apolloClient = create(initialState)
  }
  return apolloClient
}
1

1 Answers

1
votes

Actually I found the solution to this issue after reading my config file.

Here's my _app.tsx file:

I realized that I was rendering calling initApollo() in the render of App, which ended in recreating an Apollo Client every time the location was changing.

Importing directly client from the apollo definition prevents against recreating a new client at location change.

 // apollo config file
export const client = initApollo()
    import React from 'react'
    import App from 'next/app'
    import {client} from '~apollo'
    import {ApolloProvider} from '@apollo/react-hooks'

    import {Provider} from 'react-redux'
    import {ConnectedRouter} from 'connected-next-router'
    import {store} from '~store'

    interface AppProps {
      ctx: any,
      Component: any
    }

    class Application extends App<AppProps> {
        static async getInitialProps(props: AppProps) {
          const {Component, ctx} = props
          const pageProps = Component.getInitialProps ? await Component.getInitialProps(ctx) : {}
          return {pageProps}
        }
        render = () => {
            const {Component, pageProps} = this.props
            return (
                <ApolloProvider client={client}>
                  <Provider store={store}>
                    <ConnectedRouter>
                      <Component {...pageProps} />
                    </ConnectedRouter>
                  </Provider>
                </ApolloProvider>
            )
        }
    }

    export default Application