Next.js Apollo Client App Router 服务端GraphQL数据获取改造求助
解决Next.js App Router中Apollo Client服务端数据获取问题
首先明确:Next.js App Router已弃用getServerSideProps这类Pages Router的API,要实现服务端数据获取,需结合Server Components异步数据获取与服务端专用的Apollo Client实例。
步骤1:创建服务端Apollo Client实例
在lib/apollo-server.ts中构建服务端专属的Apollo Client,开启SSR模式以适配服务端渲染逻辑:
import { ApolloClient, InMemoryCache, createHttpLink } from '@apollo/client'; import { setContext } from '@apollo/client/link/context'; export function createServerApolloClient() { // 配置你的GraphQL端点 const httpLink = createHttpLink({ uri: 'https://your-graphql-endpoint.com/graphql', }); // 可选:添加服务端认证逻辑(比如从cookies或环境变量取token) const authLink = setContext((_, { headers }) => { return { headers: { ...headers, // 示例:authorization: `Bearer ${process.env.SERVER_AUTH_TOKEN}` } }; }); return new ApolloClient({ ssrMode: true, // 关键:开启SSR模式,避免客户端缓存干扰服务端请求 link: authLink.concat(httpLink), cache: new InMemoryCache(), }); }
步骤2:在Server Component中直接获取数据
App Router里app/page.tsx默认是Server Component(无需'use client'指令),可直接在组件内异步执行查询:
import { createServerApolloClient } from '@/lib/apollo-server'; // 导入你的GraphQL查询语句 import { GET_TARGET_DATA_QUERY } from '@/lib/queries'; export default async function HomePage() { // 初始化服务端Apollo Client const apolloClient = createServerApolloClient(); // 服务端同步执行GraphQL查询 const { data, error } = await apolloClient.query({ query: GET_TARGET_DATA_QUERY, // 可选:传递查询变量 // variables: { category: 'news' } }); if (error) return <div>数据加载失败:{error.message}</div>; // 直接用服务端获取的数据渲染页面 return ( <div className="page-container"> <h1>服务端渲染内容</h1> <div>{data?.targetData?.map(item => <p key={item.id}>{item.title}</p>)}</div> </div> ); }
步骤3:处理客户端交互场景
如果页面需要客户端交互(比如点击事件、状态管理),可将服务端获取的数据传递给带'use client'指令的子组件:
// app/page.tsx(Server Component) import { createServerApolloClient } from '@/lib/apollo-server'; import { GET_TARGET_DATA_QUERY } from '@/lib/queries'; import InteractiveClientComponent from './interactive-client-component'; export default async function HomePage() { const apolloClient = createServerApolloClient(); const { data } = await apolloClient.query({ query: GET_TARGET_DATA_QUERY }); // 将服务端数据传给客户端组件 return <InteractiveClientComponent serverFetchedData={data} />; } // app/interactive-client-component.tsx(Client Component) 'use client'; import { useState } from 'react'; export default function InteractiveClientComponent({ serverFetchedData }) { const [isExpanded, setIsExpanded] = useState(false); // 在这里可以使用客户端钩子、状态管理,同时直接复用服务端数据 return ( <div> <button onClick={() => setIsExpanded(!isExpanded)}> {isExpanded ? '收起' : '展开'}数据 </button> {isExpanded && <pre>{JSON.stringify(serverFetchedData, null, 2)}</pre>} </div> ); }
关键注意事项
- 不要在Server Component中使用客户端Apollo钩子(比如你之前的
ApolloHooks.tsx),React钩子仅能在客户端组件中调用 - 如果需要强制每次请求都获取最新数据(等效原
getServerSideProps的动态渲染),可在page组件顶部添加:export const dynamic = 'force-dynamic'; - 确保服务端与客户端Apollo Client的核心配置(端点、认证逻辑)一致,避免出现服务端与客户端数据不匹配的问题
内容的提问来源于stack exchange,提问作者user23254907
相关产品推荐
相关产品推荐

