useQuery 是否在服务器端渲染上运行?

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

1.我看到Nextjs有两种获取数据的方法。其中之一是使用 useQuery 钩子,但只能在 React 组件函数上调用。这是否意味着它仅在从客户端呈现页面时运行

  1. 我读了一篇关于如何将 apolloClient 连接到 Nextjs 的帖子。它说

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

这是示例代码

  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;
  }

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

stack overflow Does useQuery run on server-side rendering?
原文答案
author avatar

接受的答案

在 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 的客户端实例或其他服务器端函数。因此,您必须在使用 getStaticPathsgetStaticPropsgetServerSideProps 并需要访问 Apollo 客户端的每个页面上定义 Apollo 连接,否则服务器端调用将无法使用它。

由于第一个 rule of hooks 是它们只能在顶层(客户端)调用,因此您不能在服务器端函数中使用它们。不,您不能在 Next SSR 或 SSG 函数中运行 useQuery

您提供的示例是保持缓存同步并且是 outdated in how it is defining the client 。这是一个更符合官方文档的简化示例。


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 用户的类型)以及服务器端兼容的 query and mutation functions for Next.js


答案: