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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 19:42:48