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

Next.js中react-query的useMutation异常及通知问题排查

Next.js + react-query POST请求问题排查与修复

问题现象

  • 提交表单后新用户已成功存入MongoDB,但终端控制台提示:API resolved without sending a response for /api/users, this may result in stalled requests.
  • 当添加名称重复的用户时,useMutation的onError回调未触发,始终执行onSuccess逻辑,不符合预期

相关代码片段

1. AddingForm组件代码

/*** components ***/
import {Button, InputGroup} from "../index";

import {useMutation} from "react-query";
import {addUser} from "../../../utils/helpers/helper";


/*** form validation ***/
import {useFormik} from "formik";
import {validateInput} from "../../../utils/functions/validateInput";


const AddingForm = () => {

    const { mutate, status } = useMutation(addUser, {
        onSuccess: data => {
            console.log(data);
            const message = "success"
            alert(message)
        },
        onError: () => {
            alert("there was an error")
        },
        /*onSettled: () => {
            queryClient.invalidateQueries('create');
        }*/
    });

    const newUser = () => {
        mutate(formik.values)
    }

    const formik = useFormik({
        initialValues: {
            name: "",
            email: ""
        },
        onSubmit: newUser,
        validate: validateInput
    });



    return (
        <>
            <form onSubmit={formik.handleSubmit}>
                <InputGroup
                    label="Name"
                    name="name"
                    error={formik.errors.name}
                    isTouched={formik.touched.name}
                    {...formik.getFieldProps("name")}
                />
                <InputGroup
                    label="Email"
                    name="email"
                    error={formik.errors.email}
                    isTouched={formik.touched.email}
                    {...formik.getFieldProps("email")}
                />

                <Button disabled={!formik.values.name && !formik.values.email}
                        className={`w-full ${!formik.values.name || !formik.values.email ? 'bg-gray-200 text-gray-500' : 'bg-orange-200'}`}
                        type="submit"
                >
                    Aggiungi
                </Button>

            </form>
        </>
    )
}

export default AddingForm;

2. addUser工具函数

/*** POST new user ***/
export const addUser = async (formData) => {

    try {
        
        const { response } = await axios.post(`${BASE_URL}/api/users`, formData);
        return response.data;

    } catch (error) {
        console.log("ERROR FROM TRY/CATCH", error.message)
        return error.message
    }
}

3. API路由处理函数(pages/api/users)

import connectDB from "../../../db/connectDB";
import {getUsers, postUser, updateUser, deleteUser} from "../../../db/controllers/AddedUserController";

/**
 * @param {import('next').NextApiRequest} req
 * @param {import('next').NextApiResponse} res
 */

export default async function handler(req, res) {
    await connectDB().catch(() => res.status(405).json({error: "Connection Error"}))

    const {method} = req

    switch(method) {
        case "GET":
            await getUsers(req, res)
            break;
        case "POST":
            await postUser(req, res)
            break;
        case "PUT":
            await updateUser(req, res)
            break;
        case "DELETE":
            await deleteUser(req, res)
            break;
        default:
            res.setHeader("Allow", ["GET", "POST", "PUT", "DELETE"])
            res.status(405).end(`Method ${method} not allowed`)
    }
}

4. postUser控制器函数

/*** POST http://localhost:3000/api/users ***/
export async function postUser(req, res) {

    try {
        console.log("FORM DATA", req.body)

        if(!req.body || req.body === undefined) return res.status(404).json({error: "Form data not provided"})

        await AddedUser.create(req.body);

    } catch(error) {
        res.status(404).json({error: error.message})
    }
}

问题原因分析

  1. 终端响应警告:postUser函数中,用户创建成功的分支没有返回任何响应,Next.js无法确认请求已完成,因此抛出"未发送响应"的警告。
  2. useMutation onError不触发:addUser函数捕获错误后直接返回错误信息,而非抛出异常。react-query的useMutation仅在内部函数抛出异常时才会触发onError,返回错误值会被视为成功结果。

修复方案

1. 修复postUser控制器,确保所有分支返回响应

在用户创建成功时返回201状态码和用户数据,同时调整错误状态码更符合语义:

export async function postUser(req, res) {
    try {
        console.log("FORM DATA", req.body)

        if(!req.body || req.body === undefined) {
            return res.status(400).json({error: "Form data not provided"})
        }

        const newUser = await AddedUser.create(req.body);
        // 创建成功返回201状态和用户数据
        res.status(201).json(newUser);

    } catch(error) {
        // 重复键等数据库冲突返回409状态
        res.status(409).json({error: error.message})
    }
}

2. 修改addUser函数,抛出异常而非返回错误

让react-query能够捕获到错误,从而触发onError回调:

export const addUser = async (formData) => {
    try {
        // 修正axios解构错误:axios.post直接返回响应对象
        const response = await axios.post(`${BASE_URL}/api/users`, formData);
        return response.data;
    } catch (error) {
        console.log("ERROR FROM TRY/CATCH", error.message)
        // 抛出错误,让useMutation捕获
        throw new Error(error.response?.data?.error || error.message);
    }
}

3. 优化useMutation错误处理(可选)

可以在onError中获取具体错误信息,提升用户体验:

const { mutate, status } = useMutation(addUser, {
    onSuccess: data => {
        console.log(data);
        alert("用户添加成功")
    },
    onError: (error) => {
        alert(`添加失败:${error.message}`)
    },
    // 如果需要添加后刷新用户列表,取消注释并传入queryClient
    // onSettled: () => {
    //     queryClient.invalidateQueries('users');
    // }
});

额外注意

  • 确保AddedUser模型中已给name字段添加唯一约束,这样重复添加时MongoDB才会抛出错误。
  • 原代码中axios的解构错误:const { response } = await axios.post(...)是错误的,axios.post直接返回响应对象,应改为const response = await axios.post(...)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 10:51:11