Next.js 13中GraphQL Mutation执行异常排查求助
问题:Next.js 13中GraphQL Mutation无法执行(Query正常,表单位于Modal内)
所有Query均可正常运行,但GraphQL Mutation完全无法执行。相同代码在其他项目中可正常使用,唯一差异是当前表单位于Modal组件中。该Mutation在GraphQL Playground内可正常执行。
注册组件代码
"use client"; import React, { useContext } from "react"; import { gql, useMutation } from "@apollo/client"; import { useForm, SubmitHandler } from "react-hook-form"; import Modal from "../Modal/Modal"; import { ModalContext } from "@/app/contex/modal"; // 定义GraphQL mutation const REGISTER_USER_MUTATION = gql` mutation RegisterUser($input: RegisterInput!) { register(input: $input) { jwt user { id username email confirmed role { id } } } } `; interface RegistrationFormData { username: string; email: string; password: string; } const Register: React.FC = () => { const modalContext = useContext(ModalContext); // 确保modalContext可用 if (!modalContext) { throw new Error("ModalContext not available"); } const { modalStatus, setModalStatus } = modalContext; const { register, handleSubmit, reset, formState: { errors }, watch, } = useForm<RegistrationFormData>(); // 定义useMutation钩子 const [registerUser, { loading, error, data }] = useMutation<{ register: { jwt: string; user: User }; }>(REGISTER_USER_MUTATION); const onSubmit: SubmitHandler<RegistrationFormData> = async (data) => { try { const response = await registerUser({ variables: { input: { username: data.username, email: data.email, password: data.password, }, }, }); if (response.errors) { console.error("GraphQL errors:", response.errors); return; } console.log("用户注册响应:", response.data); reset(); } catch (err) { console.error("注册错误:", err); } }; const password = watch("password"); return ( <Modal> <h1>注册</h1> <form onSubmit={handleSubmit(onSubmit)}> <div> <label htmlFor="username">用户名</label> <input type="text" id="username" {...register("username", { required: "用户名不能为空" })} /> {errors.username && <span>{errors.username.message}</span>} </div> <div> <label htmlFor="email">邮箱</label> <input type="email" id="email" {...register("email", { required: "邮箱不能为空" })} /> {errors.email && <span>{errors.email.message}</span>} </div> <div> <label htmlFor="password">密码</label> <input type="password" id="password" {...register("password", { required: "密码不能为空" })} /> {errors.password && <span>{errors.password.message}</span>} </div> <div> <label htmlFor="confirmPassword">确认密码</label> <input type="password" id="confirmPassword" {...register("confirmPassword", { required: "请确认密码", validate: (value) => value === password || "密码不匹配", })} /> {errors.confirmPassword && ( <span>{errors.confirmPassword.message}</span> )} </div> <div> <button type="submit">注册</button> </div> </form> <button onClick={() => { setModalStatus(""); }} > 关闭 </button> </Modal> ); }; export default Register;
lib/apollo-wrapper.js代码
"use client"; import { ApolloClient, ApolloLink, HttpLink, } from "@apollo/client"; import { ApolloNextAppProvider, NextSSRInMemoryCache, SSRMultipartLink, NextSSRApolloClient } from "@apollo/experimental-nextjs-app-support/ssr"; function makeClient() { const httpLink = new HttpLink({ uri: process.env.NEXT_PUBLIC_API_ENDPOINT, }); return new NextSSRApolloClient({ cache: new NextSSRInMemoryCache(), link: typeof window === "undefined" ? ApolloLink.from([ new SSRMultipartLink({ stripDefer: true, }), httpLink, ]) : httpLink, }); } export function ApolloWrapper({ children }) { return ( <ApolloNextAppProvider makeClient={makeClient}> {children} </ApolloNextAppProvider> ); }
lib/client.js代码
import { ApolloClient, HttpLink, InMemoryCache } from "@apollo/client"; import { NextSSRInMemoryCache, NextSSRApolloClient, } from "@apollo/experimental-nextjs-app-support/ssr"; import { registerApolloClient } from "@apollo/experimental-nextjs-app-support/rsc"; export const { getClient } = registerApolloClient(() => { return new NextSSRApolloClient({ cache: new NextSSRInMemoryCache(), link: new HttpLink({ uri: process.env.NEXT_PUBLIC_API_ENDPOINT, }), }); });
排查与解决方案
1. 检查Modal组件的事件拦截
很多自定义Modal会默认阻止事件冒泡或表单默认提交行为,导致onSubmit无法触发:
- 在
onSubmit开头添加console.log("表单提交触发"),确认函数是否被调用 - 检查Modal组件的根元素,是否存在
onClick事件中调用e.preventDefault()或e.stopPropagation(),如果有,修改逻辑避免影响表单提交
2. 修复React Hook Form的类型定义错误
你的RegistrationFormData接口未包含confirmPassword字段,但表单中使用了该字段,会导致类型校验失败,阻止表单提交。修改接口:
interface RegistrationFormData { username: string; email: string; password: string; confirmPassword: string; // 添加该字段 }
3. 确认Apollo上下文覆盖范围
确保ApolloWrapper包裹了整个应用(包括Modal的渲染层级),否则组件无法获取Apollo客户端实例。可以在Register组件内添加以下代码验证:
import { useApolloClient } from '@apollo/client'; // 组件内部 const client = useApolloClient(); console.log("Apollo客户端是否可用:", !!client);
如果输出false,需要调整ApolloWrapper的位置,确保Modal在其覆盖范围内。
4. 排查Apollo配置冲突
你同时维护了apollo-wrapper.js和client.js两个配置,确认:
- 应用根布局(如
app/layout.js)仅使用ApolloWrapper包裹,未重复引入其他Apollo客户端 - 浏览器开发者工具的Network标签中,查看Mutation请求是否发送,是否存在跨域错误或4xx/5xx状态码
5. 完善错误日志
在onSubmit中添加更详细的日志,定位问题:
const onSubmit: SubmitHandler<RegistrationFormData> = async (data) => { console.log("提交的表单数据:", data); console.log("开始调用Mutation"); try { const response = await registerUser({ variables: { input: { username: data.username, email: data.email, password: data.password, }, }, }); console.log("Mutation响应:", response); // 原有逻辑 } catch (err) { console.error("完整错误信息:", JSON.stringify(err, null, 2)); } };
内容的提问来源于stack exchange,提问作者Gilbert Lucas
相关产品推荐
相关产品推荐

