首页 > 解决方案 > useQuery 是否在服务器端渲染上运行?

问题描述

我是 Nextjs 新手,对 Nextjs 中的客户端渲染和服务器端渲染有一些疑问

  1. 我看到有两种方法可以在 Nextjs 上获取数据。其中之一是使用useQuery钩子,但只能在 React 组件函数上调用。这是否意味着它仅在从客户端呈现页面时运行
  2. 我读了一篇关于如何连接apolloClient到 Nextjs 的文章。它说

总是apolloClient为 SSR 创建一个新实例,并且只apolloClient为 CSR创建一个实例

这是示例代码

  export function initializeApollo(initialState = null) {
    const _apolloClient = apolloClient ?? createApolloClient();

    // If your page has Next.js data fetching methods that use Apollo Client,
    // the initial state gets hydrated here
    if (initialState) {
      // Get existing cache, loaded during client side data fetching
      const existingCache = _apolloClient.extract();

      // Restore the cache using the data passed from
      // getStaticProps/getServerSideProps combined with the existing cached data
      _apolloClient.cache.restore({ ...existingCache, ...initialState });
    }

    // For SSG and SSR always create a new Apollo Client
    if (typeof window === "undefined") return _apolloClient;

    // Create the Apollo Client once in the client
    if (!apolloClient) apolloClient = _apolloClient;
    return _apolloClient;
  }

谁能解释一下?如果问题很愚蠢,我很抱歉

标签: next.jsapolloapollo-client

解决方案


在 Next JS 中:

  • SSR - 服务器端渲染 -getServerSideProps
  • SSG - 生成的静态站点 - getStaticPaths&getStaticProps
  • CSR - 客户端渲染 - 其他一切

需要注意的是,SSG 函数是在服务器端运行的。

在客户端上,您只想创建一个 Apollo Client 的全局实例。创建多个 Apollo 客户端实例将使与客户端保持同步变得具有挑战性。这个困难是因为 Apollo Cache、Apollo Link 等,都会存储在不同的 Apollo Client 实例中。

在 Next 中,常见的是将 Apollo Client 的全局实例放在页面上_app.js,并使用Apollo Provider。在其他客户端页面上,您将使用useQuery调用单个全局实例的钩子。

服务器端 (SSR) 功能getStaticPropsgetServerSideProps无权访问 Apollo 的客户端实例、Next 的客户端实例或其他服务器端功能。因此,您必须在每个使用 、 或 并且需要访问 Apollo 客户端的页面上定义 Apollo 连接getStaticPathsgetStaticProps否则getServerSideProps服务器端调用将无法使用它。

由于钩子的第一条规则是它们只能在顶层(客户端)调用,因此您不能在服务器端函数中使用它们。不,您不能useQuery在 Next SSR 或 SSG 功能中运行。

您提供的示例是保持缓存同步,并且在定义客户端方面已经过时。这是一个更符合官方文档的简化示例。


graphqlClient.js

import { ApolloClient, HttpLink, InMemoryCache } from '@apollo/client';

// Used server and client side - can't use react hooks
export const graphqlClient = new ApolloClient({
  cache: new InMemoryCache(),
  link: new HttpLink({
    uri: 'YOUR_GQL_ENDPOINT',
  }),
  ssrMode: typeof window === 'undefined',
});

_app.js - 所有客户端页面都使用的单个实例,因为它包装了整个应用程序

import graphqlClient from 'my/path/graphqlClient';

const App = ({ Component, pageProps }) => {
  const client = graphqlClient();
  return (
    <ApolloProvider client={client}>
      <Component {...pageProps} />
    </ApolloProvider>
  );
};

客户端的每个页面/组件都可以使用 useQuery 钩子,因为 Apollo Client 将应用程序包装在_app.js

客户端查询

import { gql, useQuery } from '@apollo/client';

const About = () => {
 const { data } = useQuery(YOUR_QUERY); // uses your single instance defined in _app.js
 return (
   ...
 )
}

每个使用 SSR 或 SSG 功能并需要访问 Apollo 的页面都必须实例化一个新的 Apollo 实例。

SSG

import graphqlClient from 'my/path/graphqlClient';

//does not have access to _app.js or client and must define new Apollo Client instance
export const getStaticProps = async () => {
  const client = graphqlClient();//
  const { data } = await client.query({query: YOUR_QUERY});
};

export const getStaticPaths = async () => {
  const client = graphqlClient();
  const { data } = await client.query({query: YOUR_QUERY});
};

固态继电器

import graphqlClient from 'my/path/graphqlClient';

//does not have access to _app.js or client and must define new Apollo Client instance
export const getServerSideProps = async () => {
  const client = graphqlClient();
  const { data } = await client.query({query: YOUR_QUERY});
};

最后,为了简化事情,您可以使用graphql-code-generator自动生成 Apollo 查询、变异等钩子(以及 TS 用户的类型)以及用于 Next.js 的服务器端兼容查询和变异函数


推荐阅读