Apollo客户端读取firstName报错:注册数据返回undefined求助
问题:Apollo Client注册用户时返回undefined,触发"Cannot read properties of undefined (reading 'firstName')"错误
我在开发Facebook克隆项目的用户注册功能,使用Apollo Server和Apollo Client。后端mutation能正常创建用户并写入数据库,但客户端调用时返回的数据为undefined,触发错误:ApolloError: Cannot read properties of undefined (reading 'firstName')。登录功能已在客户端实现,代码逻辑与注册基本一致(仅addUser mutation使用了输入类型),无法定位问题。前端基于React框架。
服务器代码
类型定义
input AddUserInput { firstName: String! lastName: String! email: String! password: String! confirmPassword: String! pronoun: String genderIdentity: String! birthYear: Int! birthMonth: Int! birthDay: Int! } type Mutation { addUser(addUserInput: AddUserInput): Auth! login(email: String!, password: String!): Auth! }
解析器
module.exports = { Mutation: { // User registration async addUser( _, { addUserInput: { firstName, lastName, email, password, confirmPassword, pronoun, genderIdentity, birthYear, birthMonth, birthDay, }, } ) { // Validate user data const { errors, valid } = validateAddUserInput( firstName, lastName, email, password, confirmPassword, pronoun, genderIdentity, birthYear, birthMonth, birthDay ); if (!valid) { console.log('bonk on user registration'); throw new UserInputError('Errors', { errors }); } // Make sure user doesn't already exist const user = await User.findOne({ email }); if (user) { throw new UserInputError('Email address is taken', { errors: { email: 'This email address is taken', }, }); } // hash the password and create an auth token const hashedPassword = await bcrypt.hash(password, 12); // save birthday as ISO 8601 string const birthday = dayjs(`${birthYear}-${birthMonth}-${birthDay}`).toISOString(); const newUser = new User({ createdAt: new Date().toISOString(), firstName, lastName, email, password: hashedPassword, gender: { pronoun, genderIdentity, }, birthday, }); const res = await newUser.save(); const { _id } = res; const token = signToken({ email, firstName, lastName, _id, }); return { user: res, id: _id, token, }; }, }, }
客户端代码
客户端Mutation
import { gql } from '@apollo/client'; export const REGISTER_USER = gql` mutation AddUser($registerInput: RegisterInput) { addUser(registerInput: $registerInput) { token user { _id firstName lastName } } } `;
注册组件(相关代码)
// Mutation const [addUser, { data, loading, error }] = useMutation(REGISTER_USER); // Registration form submit function const handleRegistrationFormSubmit = async (event) => { event.preventDefault(); // Make a copy of the registration form inputs const registrationFormInputs = { ...registrationForm }; // Format gender inputs for the API if (registrationForm.customGender === '') { delete registrationFormInputs.customGender; } else { registrationFormInputs.genderIdentity = registrationFormInputs.customGender; delete registrationFormInputs.customGender; } try { const { data } = await addUser({ variables: { ...registrationFormInputs }, }); // Get login token from response const registrationToken = data.register.token; Auth.login(registrationToken); // Clear the register form setRegistrationForm({ firstName: '', lastName: '', emailAddress: '', password: '', confirmPassword: '', birthDay: dayCurrent, birthMonth: monthCurrent, birthYear: yearCurrent, gender: '', pronoun: '', customGender: '', }); return <Navigate to="/" />; } catch (e) { ... } };
已尝试的解决方法
- 修改mutation名称
- 在客户端mutation中逐个添加类型
以上方法均未解决问题。
问题排查与解决方案
1. 客户端Mutation参数与后端定义不匹配
后端mutation接收的参数名为addUserInput,输入类型是AddUserInput,但客户端Mutation里写成了registerInput和RegisterInput,导致参数无法正确映射。
修正后的客户端Mutation:
import { gql } from '@apollo/client'; export const REGISTER_USER = gql` mutation AddUser($addUserInput: AddUserInput) { addUser(addUserInput: $addUserInput) { token user { _id firstName lastName } } } `;
2. 客户端调用mutation时变量传递错误
后端期望接收一个包含addUserInput的对象参数,而不是直接展开表单字段。
修正调用代码:
const { data } = await addUser({ variables: { addUserInput: registrationFormInputs }, });
3. 返回数据解析键名错误
客户端代码中写的data.register.token是错误的,后端mutation返回的字段是addUser,正确的解析方式是data.addUser.token,这是导致undefined的直接原因。
修正后的解析代码:
const registrationToken = data.addUser.token; // 若要访问用户信息,需用 data.addUser.user.firstName
4. 表单字段名不匹配
检查到表单中使用的是emailAddress,但后端期望的字段是email,需要将表单中的emailAddress改为email,否则后端会因缺少邮箱参数触发验证错误。
内容的提问来源于stack exchange,提问作者TheInfamousGrim
相关产品推荐
相关产品推荐

