如何使用 Apollo Client useQuery 挂钩防止不必要的重新获取?

How to prevent unnecessary refetch using Apollo Client useQuery hook?

我正在尝试使用 Apollo 客户端实现一个 CRUD 应用程序,使用 nextJS 和无服务器框架作为 GraphQL 后端。 有什么方法可以防止在使用缓存的应用程序导航期间进行不必要的自动重新获取?

例如,我正在创建一个带有突变的新记录,添加 refetchQueries 将刷新缓存,但假设用户正在导航到另一个视图,然后使用 useQuery 挂钩返回到该视图,数据将被再次获取,但它应该已经在缓存中。

这是我的 ApolloClient 配置:

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
}

实际上我在阅读我的配置文件后找到了解决这个问题的方法。

这是我的 _app.tsx 文件:

我意识到我在应用程序的渲染中渲染调用 initApollo(),每次位置发生变化时都会重新创建一个 Apollo 客户端。

直接从 apollo 定义中导入 client 可防止在位置更改时重新创建新客户端。

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