Next.js搭配Apollo时服务端获取URL参数作为GraphQL查询变量问题
核心解决方案
你遇到的问题本质是getServerSideProps运行在服务端,无法访问客户端的路由实例,且动态路由参数本身可以通过getServerSideProps的入参直接获取,不需要从组件侧导出变量。
第一步:修改页面的getServerSideProps逻辑
直接从getServerSideProps的上下文参数中取动态路由的slug值,删掉之前引入的写死的userQueryVars变量即可:
import App from "../../../components/App" import Header from "../../../components/Header" import UserProfile, { USER_QUERY, } from "../../../components/UserProfile" // 删掉userQueryVars的引入 import { initializeApollo, addApolloState } from "../../../lib/apolloClient" const UserProfilePage = () => ( <App> <Header /> <UserProfile /> </App> ) export async function getServerSideProps(context) { const apolloClient = initializeApollo() // 直接从上下文获取动态路由参数 const slug = context.query.slug await apolloClient.query({ query: USER_QUERY, variables: { slug }, }) return addApolloState(apolloClient, { props: {} }) } export default UserProfilePage
第二步:优化组件的请求容错
给useQuery添加跳过逻辑,避免路由还没初始化完成时,slug为undefined触发GraphQL参数校验报错,同时删掉组件里没用的userQueryVars导出:
import { gql, useQuery } from "@apollo/client" import ErrorMessage from "./ErrorMessage" import { useRouter } from "next/router"; export const USER_QUERY = gql` query getUser($slug: String!) { user(slug: $slug) { id email firstName lastName } } ` // 删掉没用的userQueryVars导出 export default function UserProfile() { const router = useRouter() const userSlug = router.query.slug const { loading, error, data } = useQuery(USER_QUERY, { variables: {slug: userSlug}, // slug不存在时跳过请求,避免参数错误 skip: !userSlug, }) if (error) return <ErrorMessage message="加载用户信息出错" /> if (loading) return <div>加载中</div> if (!data) return <div>无数据</div> const { user } = data return ( <section> <div> <h3> {user.firstName} {user.lastName} </h3> <p>{user.email}</p> </div> </section> ) }
之前尝试报错的原因
useRouter是仅客户端可用的Hook,只能在React组件的函数体内调用,你在组件顶层导出变量时调用,服务端编译阶段就会执行,自然会触发客户端环境限制报错。- ES模块规范要求
import、export语句必须出现在代码顶层,不能包裹在if等条件判断内,所以加环境判断再导出的写法不符合语法规则。
内容的提问来源于stack exchange,提问作者kampfkuchen
相关产品推荐
相关产品推荐

