You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Next.js 14:如何在SSR组件中调用GraphQL查询(无需"use client")

实现Next.js SSR产品页(无需"use client")获取GraphQL数据

背景

已完成Next.js项目搭建并配置Apollo Client,RootLayout中通过ApolloProviderClient包裹子组件。现需创建产品页,要求通过SSR渲染所有产品以满足SEO需求,且不使用"use client"指令。

解决方案

Next.js App Router中默认组件为服务器组件,可直接调用Apollo Client的client.query()方法在服务器端获取GraphQL数据,无需依赖客户端hooks(如useQuery),自然无需"use client"。

步骤1:调整Apollo Client的授权逻辑

原Client代码中使用了浏览器专属的sessionStorage/localStorage,服务器端无法访问,需修改为区分环境的token获取逻辑:

// @/utils/apollo-clients.ts
import { ApolloClient, createHttpLink, InMemoryCache } from "@apollo/client";
import { setContext } from "@apollo/client/link/context";
import { baseUrl } from "@/utils/constant/baseUrl";
import { cookies } from "next/headers";

const httpLink = createHttpLink({
  uri: baseUrl,
});

const authLink = setContext((_, { headers }) => {
  let token = "";
  // 区分服务器/客户端环境
  if (typeof window === "undefined") {
    // 服务器端从Cookie获取token
    const cookieStore = cookies();
    token = cookieStore.get("accessToken")?.value || "";
  } else {
    // 客户端沿用原有逻辑
    const sessionToken = sessionStorage.getItem("accessToken");
    const localToken = localStorage.getItem("accessToken");
    token = sessionToken || localToken || "";
  }
  return {
    headers: {
      ...headers,
      Authorization: token ? `Bearer ${token}` : "",
    },
  };
});

export const client = new ApolloClient({
  link: authLink.concat(httpLink),
  cache: new InMemoryCache(),
});

步骤2:定义GraphQL查询语句

创建查询文件存放产品列表的GraphQL查询:

// @/queries/products.ts
import { gql } from "@apollo/client";

export const GET_PRODUCTS = gql`
  query GetProducts {
    products {
      id
      name
      description
      price
      # 按需添加其他字段
    }
  }
`;

步骤3:创建SSR产品页(服务器组件)

在app/products/page.tsx创建服务器组件,直接调用Apollo Client获取数据并渲染:

// app/products/page.tsx
import { client } from "@/utils/apollo-clients";
import { GET_PRODUCTS } from "@/queries/products";

// 默认服务器组件,无需"use client"
export default async function ProductsPage() {
  // 服务器端异步获取产品数据
  const { data, error } = await client.query({
    query: GET_PRODUCTS,
    // 如需传参可添加variables: { category: "electronics" }等
  });

  // 处理错误
  if (error) {
    return <div>产品加载失败:{error.message}</div>;
  }

  const products = data.products;

  return (
    <div className="products-container">
      <h1>全部产品</h1>
      <div className="products-grid">
        {products.map((product) => (
          <div key={product.id} className="product-card">
            <h3>{product.name}</h3>
            <p>{product.description}</p>
            <span className="price">${product.price}</span>
          </div>
        ))}
      </div>
    </div>
  );
}

关键说明

  • 该组件为服务器组件,数据在服务器端预获取后直接渲染为HTML,完全满足SEO需求,无需客户端 hydration 即可展示内容。
  • 服务器组件中无需包裹ApolloProvider,直接使用Apollo Client实例完成数据查询。
  • 调整后的Client逻辑兼容服务器/客户端环境,避免服务器端因访问浏览器API报错。

内容的提问来源于stack exchange,提问作者Asit singh

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 04:17:10