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

React中Toast显示错误代码而非实际消息的问题排查

问题描述

调用用户注册API后,无法正常显示错误或成功消息。当用户已存在时,API返回User already exists,但Toast却显示Request failed with status code 409——尽管开发者工具里能看到实际的响应内容。以下是相关的Redux异步action代码和React组件代码,无法定位问题出在API返回处理还是组件捕获逻辑上。


相关代码

Redux异步Action代码

export const registerUser = (payload: RegisterPayload) => async (dispatch: AppDispatch) => {
    dispatch(registerStart());
    try {
        const response = await axiosClient.post('/register', payload);

        let successMessage = 'Operation successful';
        if (response.data?.detail) {
            successMessage = response.data.detail
                .map((msg: string) => {
                    const message = msg;
                    const commaIndex = message.indexOf(':');

                    // 检查是否存在冒号并裁剪消息
                    if (commaIndex !== -1) {
                        return message.substring(commaIndex + 2);
                    }
                    return message;
                })
                .join(', ');
        }

        dispatch(registerSuccess(response.data));
        dispatch(showToast({ message: successMessage, type: 'success' }));
        return { success: true, data: response.data, message: successMessage };
    } catch (error: any) {
        let errorMessage = 'An error occurred';

        // 处理FastAPI的detail列表错误
        if (error.response && Array.isArray(error.response.data?.detail)) {
            // 从detail列表提取消息
            errorMessage = error.response.data.detail
                .map((err: { msg: string }) => {
                    const errorMsg = err.msg;
                    const commaIndex = errorMsg.indexOf(', ');

                    // 检查是否存在逗号并裁剪消息
                    if (commaIndex !== -1) {
                        return errorMsg.substring(commaIndex + 2);
                    }
                    return errorMsg;
                })
                .join(', ');
        } else if (error.response?.data?.error) {
            errorMessage = error.response.data.error;
        } else if (error.message) {
            errorMessage = error.message;
        }

        dispatch(registerFailure(errorMessage));
        dispatch(showToast({ message: errorMessage, type: 'error' }));
        return { success: false, message: errorMessage };
    }
};

React组件代码

const initialValues={
    firstname: '',
    lastname: '',
    username: '',
    email: '',
    password: '',
    changepassword: '',
}

const UserRegistration: React.FC = () => {
    const dispatch = useAppDispatch();
    const [errorMessage, setErrorMessage] = useState<string | null>(null);
    const [successMessage, setSuccessMessage] = useState<string | null>(null);
    const { loading } = useAppSelector((state) => state.user);

    const handleApiResponse = (result: { success: boolean; message?: string; data?: any }) => {
        if (!result.success) {
            const errorMessage = result.message ?? 'An unknown error occurred';
            setErrorMessage(errorMessage);
            dispatch(showToast({ message: errorMessage, type: 'error' }));
        } else {
            const successMessage = result.message ?? 'Operation successful';
            setSuccessMessage(successMessage);
            dispatch(showToast({ message: successMessage, type: 'success' }));
        }
    };

    const handleSubmit = async (values: typeof initialValues, { setSubmitting }: { setSubmitting: (isSubmitting: boolean) => void }) => {
        const apiValues: RegisterPayload = {
            first_name: values.firstname,
            last_name: values.lastname,
            username: values.username,
            email: values.email,
            password: values.password,
            password_confirm: values.changepassword,
        };

        try {
            const apiResponse = await dispatch(registerUser(apiValues));
            handleApiResponse(apiResponse);
        } catch (error: any) {
            if (error.message) handleApiResponse(error);
        } finally {
            setSubmitting(false);
        }
    };

    const formik = useFormik({
        initialValues,
        validationSchema: UserRegistrationSchema,
        onSubmit: handleSubmit,
    });

    return (
            // 表单代码省略
    )
};

export default UserRegistration;

问题定位与修复

1. 核心问题:错误响应的判断逻辑不全

当用户已存在时,API返回的detail是字符串类型,但你的Redux Action只处理了detail为数组的情况,导致匹配不到正确的分支,最终走了else if (error.message),使用了axios默认的错误提示Request failed with status code 409。

修复Redux Action的错误处理逻辑

修改catch块,增加对字符串类型detail的判断:

catch (error: any) {
    let errorMessage = 'An error occurred';

    if (error.response) {
        // 处理FastAPI的detail:兼容数组和字符串两种格式
        if (error.response.data?.detail) {
            if (Array.isArray(error.response.data.detail)) {
                // 数组类型detail,提取msg内容
                errorMessage = error.response.data.detail
                    .map((err: { msg: string }) => {
                        const errorMsg = err.msg;
                        const commaIndex = errorMsg.indexOf(', ');
                        if (commaIndex !== -1) {
                            return errorMsg.substring(commaIndex + 2);
                        }
                        return errorMsg;
                    })
                    .join(', ');
            } else {
                // 字符串类型detail,直接使用
                errorMessage = error.response.data.detail;
            }
        } else if (error.response.data?.error) {
            errorMessage = error.response.data.error;
        }
    } else if (error.message) {
        // 处理无响应的网络错误
        errorMessage = error.message;
    }

    dispatch(registerFailure(errorMessage));
    dispatch(showToast({ message: errorMessage, type: 'error' }));
    return { success: false, message: errorMessage };
}

2. 次要问题:组件中冗余的Toast调用

你的Redux Action已经调用了showToast,但组件的handleApiResponse又重复调用了一次,会导致Toast重复显示。同时,handleSubmit中的try/catch是多余的——因为Action内部已经捕获了错误并返回结果,不会抛出异常。

修复React组件的冗余逻辑

// 修改handleApiResponse,移除重复的Toast调用
const handleApiResponse = (result: { success: boolean; message?: string; data?: any }) => {
    if (!result.success) {
        const errorMessage = result.message ?? 'An unknown error occurred';
        setErrorMessage(errorMessage);
    } else {
        const successMessage = result.message ?? 'Operation successful';
        setSuccessMessage(successMessage);
    }
};

// 修改handleSubmit,移除多余的try/catch
const handleSubmit = async (values: typeof initialValues, { setSubmitting }: { setSubmitting: (isSubmitting: boolean) => void }) => {
    const apiValues: RegisterPayload = {
        first_name: values.firstname,
        last_name: values.lastname,
        username: values.username,
        email: values.email,
        password: values.password,
        password_confirm: values.changepassword,
    };

    const apiResponse = await dispatch(registerUser(apiValues));
    handleApiResponse(apiResponse);
    setSubmitting(false);
};

内容的提问来源于stack exchange,提问作者Jazzman

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 18:13:10