如何使用 Apollo 客户端 useQuery 钩子防止不必要的重新获取?

Posted

技术标签:

【中文标题】如何使用 Apollo 客户端 useQuery 钩子防止不必要的重新获取?【英文标题】:How to prevent unnecessary refetch using Apollo Client useQuery hook? 【发布时间】:2020-07-25 14:57:43 【问题描述】:

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

例如,我正在创建一个带有突变的新记录,添加 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,
    s-s-rMode: 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】:

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

这是我的_app.tsx 文件:

我意识到我在 App 的渲染中渲染调用 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

【讨论】:

以上是关于如何使用 Apollo 客户端 useQuery 钩子防止不必要的重新获取?的主要内容,如果未能解决你的问题,请参考以下文章

如何从 Apollo 客户端的 useQuery 获取响应头

Apollo 客户端没有读取使用 useQuery 钩子传入的变量

Apollo 客户端 fetchMore 来自 useQuery 触发两个网络请求

react native apollo client useQuery invalid hook call error

Apollo 客户端 useQuery 在 useMutation 后不更新数据

@apollo/client 反应钩子 useQuery() 数据未定义