Next.js中Select选择值收集失败,点击按钮无响应问题排查
问题修复方案
前端页面(page.jsx)问题修复
- 初始化useRouter:组件内仅导入
useRouter但未实例化,导致router.push报错 - 替换请求方法:GET请求不支持携带body参数,改为POST传递筛选条件
- 正确解析响应:需先调用
await res.json()获取响应体,不能直接访问res.data - 修正提示逻辑:成功状态改用成功提示,避免错误提示混淆
- 恢复表单校验:启用空值校验,防止无效提交
修改后的page.jsx代码:
"use client"; import { useRouter } from "next/navigation"; import { useState } from "react"; import { useSession } from "next-auth/react"; import { toast } from "react-toastify"; import { Select, Option } from "@material-tailwind/react"; const Selectt = () => { const [subject, setSubject] = useState(""); const [grade, setGrade] = useState(""); const [show, setShow] = useState(false); // 初始化router实例 const router = useRouter(); const handleSelect = async () => { // 校验必填项 if (!subject || !grade ) { toast.error("Hãy chọn đầy đủ các mục!"); return; } try { const res = await fetch("/api/quiz/FilterQuestion", { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify({ subject, grade }), }); const responseData = await res.json(); if (res.status === 400) { toast.error("Không tồn tại câu hỏi thỏa mãn", { position: toast.POSITION.TOP_CENTER, className: "foo-bar", }); router.push("/thithu"); } else if (res.status === 201) { console.log(responseData.data[0]); router.push("/home"); toast.success("Có câu hỏi thỏa mãn!"); } else { router.push("/blog"); toast.error("Quá khó!"); } } catch (error) { toast.error(error.message); } }; return ( <> <div className={`${show?'pointer-events-none opacity-0':''} flex flex-row items-center justify-center w-1/2 gap-10 m-auto`}> <Select label="Chọn môn" color="purple" animate={{ mount: { y: 0 }, unmount: { y: 25 } }} value={subject} onChange={(subject) => setSubject(subject)} > <Option value="math">Toán</Option> <Option value="physics">Vật lí</Option> <Option value="chemistry">Hóa học</Option> </Select> <Select label="Chọn lớp" color="blue" animate={{ mount: { y: 0 }, unmount: { y: 25 } }} value={grade} onChange={(grade) => setGrade(grade)} > <Option value="9">Lớp 9</Option> <Option value="10">Lớp 10</Option> <Option value="11">Lớp 11</Option> <Option value="12">Lớp 12</Option> </Select> </div> <div className="flex m-auto"> <button className={`${show?'pointer-events-none opacity-0 text-none':''}bg-green-200 mt-3 p-2 rounded-md m-auto`} onClick={handleSelect} > Select </button> </div> </> ); }; export default Selectt;
后端API(route.js)问题修复
- 对应请求方法:将GET改为POST,匹配前端请求
- 异步获取查询结果:
find()是异步方法,必须加await才能拿到真实数据 - 正确判断结果存在性:通过数组长度判断是否有匹配数据,而非直接判断对象
- 修正响应写法:使用
NextResponse.json()正确生成JSON响应 - 统一异常处理:将数据库查询逻辑放入try块,捕获并处理查询错误
修改后的route.js代码:
import Question from "models/Question"; import connectDB from "config/question_database"; import { NextResponse } from "next/server"; export const POST = async (request) => { try { await connectDB(); const { subject, grade} = await request.json(); console.log(subject, grade); // 等待查询结果返回 const selectedQuestion = await Question.find({ subject: subject, class: grade }); // 检查是否有匹配数据 if (selectedQuestion.length === 0) { console.log("Không tồn tại câu hỏi thỏa mãn"); return NextResponse.json( { error: "Không tồn tại câu hỏi thỏa mãn yêu cầu" }, { status: 400 } ); } else { console.log("Thành công"); return NextResponse.json( { data: selectedQuestion }, { status: 201 } ); } } catch (error) { console.error("Lỗi truy vấn cơ sở dữ liệu:", error); return NextResponse.json( { error: "Lỗi khi xử lý yêu cầu" }, { status: 500 } ); } };
核心问题总结
- HTTP GET请求不支持携带body参数,改用POST才能正确传递筛选条件
- MongoDB的
find()是异步操作,必须使用await获取实际查询结果 - 前端未初始化router实例导致页面跳转功能失效
- 响应数据处理错误,需先解析JSON才能访问返回内容
内容的提问来源于stack exchange,提问作者David Nguyen
相关产品推荐
相关产品推荐

