作为道具传递与提取缓存 Apollo 客户端 Nextjs

Posted

技术标签:

【中文标题】作为道具传递与提取缓存 Apollo 客户端 Nextjs【英文标题】:Passing as Props vs Extracting Cache Apollo Client Nextjs 【发布时间】:2021-07-10 22:52:03 【问题描述】:

我在apollo-client repo 中发布了这个,但我想我也会问 ***

你好!我是 apollo(以及整个 graphql)的新手,并且对 s-s-r / SSG 有一些疑问。我在概念上知道什么是 s-s-r/SSG 以及它是如何工作的,但对 apollo-client 了解不多。

我已经尝试在网上搜索和搜索正确执行此操作的方法,并且看到两个版本几乎没有解释原因,所以我在这篇文章中的目标是有一个地方指出并去“这就是你这样做的原因一个比一个”。

这样做有什么好处/坏处

这是 TypeScript 和伪代码的混合体,请不要批评语法 kthx

// apolloClient.ts
const client = new ApolloClient(
  link: new HttpLink( uri: '/graphql' ),
  cache: new InMemoryCache(),
);
// component.tsx
import client from '../apolloClient';

const Component: FunctionalComponent = ( data ) => 
   ...


export const getServerSideProps: GetServerSideProps = async () => 
  const  data  = client.query(...);

  return 
    props:  data 
  

// app.tsx
import client from './client';

const MyApp: NextComponentType<AppContext, AppInitialProps, AppProps> = ( Component, pageProps ) => (
  <ApolloProvider client=client>
    <Component ...pageProps />
  </ApolloProvider>
);

VS

// apolloClient.ts
const createClient = () => new ApolloClient(
  link: new HttpLink( uri: '/graphql' ),
  cache: new InMemoryCache(),
  s-s-rMode: typeof window === 'undefined',
);

let client: ApolloClient<NormalizedCacheObject>;
const initalizeApollo = (initalState?: NormalizedCacheObject) => 
  const apolloClient = client ?? createClient();

  if (initalState) 
    apolloClient.cache.restore(
      ...apolloClient.cache.extract(),
      ...initalState,
    );
  

  if (typeof window === 'undefined') return apolloClient;

  client ??= apolloClient;

  return client;


const useApollo = (initalState?: NormalizedCacheObject) => useMemo(() => initalizeApollo(initalState), [initalState]);
// component.tsx
import  useQuery  from 'apollo-client';
import useApollo from '../apolloClient';

const Component = () => 
   const  data  = useQuery(...);


export const getServerSideProps: GetServerSideProps = async () => 
  const client = useApollo();

  await client.query(...);

  return 
    props:  initalApolloState: client.cache.extract() 
  

// app.tsx
const MyApp: NextComponentType<AppContext, AppInitialProps, AppProps> = ( Component, pageProps ) => 
  const client = useApollo(pageProps.initalApolloState);

  return (
    <ApolloProvider client=client>
      <Component ...pageProps />
    </ApolloProvider>
  )
;

这是我自己的“我不明白”部分的讨论

对我来说,似乎是第二种方式(使用 s-s-r?)您必须运行两次查询并编写大量额外代码才能获得相同的效果?这两种方法的性能/安全性/任何好处是什么。

谢谢!

【问题讨论】:

【参考方案1】:

您的第一种方法更符合 Next 试图做的事情。它希望在构建时通过getStaticProps (SSG) 或getServerSideProps (s-s-r) 为页面提取数据。这个想法是它会尽可能在服务器上静态生成页面。

getStaticProps/getServerSideProps 调用中不需要引用 Apollo 客户端。我认为您可以使用 Context 并且甚至不需要像您的代码编写方式那样需要 Apollo Client。

我在 Next 应用程序中使用 Apollo 的地方是我需要将数据拉入组件。 Next 对此并没有真正的答案,但这是 Apollo 做得很好的地方。一个好的用例是出现在每个页面上的菜单。如果您更改菜单项,您不希望触发站点范围的静态重新生成。 Apollo 将保持所有页面新鲜,不会触发 Next 再次渲染。

概述我一直在做的事情in this answer。

【讨论】:

以上是关于作为道具传递与提取缓存 Apollo 客户端 Nextjs的主要内容,如果未能解决你的问题,请参考以下文章

突变后 React Apollo 客户端道具 refetchQueries

使用 apollo Query 传递 Apollo 客户端缓存数据

Apollo:数据/突变道具未传递给组件

是否可以将变量传递给 react-apollo 的“儿童”道具?

如何使用 Apollo 更改道具上的查询?

如何从 json 中提取数据并在 Next.js 中作为 props 传递