如何实现点击按钮将Quiz得分提交至数据库的前端功能
测验应用前端得分提交实现方案
问题背景
开发了一款支持用户自测、自动计算得分的测验应用,需要实现点击「提交得分」按钮后将得分写入数据库的逻辑。
目前已完成数据模型、控制器中score字段的相关配置,且通过Postman验证后端接口运行正常,得分可成功写入数据库,仅剩余前端提交逻辑待开发。
现有代码
后端代码
FormController.js
const form = require('../models/FormModel') module.exports = { store: (req, res, next) => { let candidate = new form({ fname: req.body.fname, lname: req.body.lname, score: req.body.score }) if (req.file) { candidate.cv = req.file.path } candidate.save() .then(response => { res.json({ success: true, message: 'Candidate added successfully!', data: candidate, }) }) .catch(error => { res.json({ success: false, message: 'An error occured!', error: error, }) }) } }
FormModel.js
const mongoose = require('mongoose') const Schema = mongoose.Schema const formSchema = new Schema({ fname: { type: String }, lname: { type: String }, score: { type: Number } }, { timestamps: true }) const form = mongoose.model('form', formSchema) module.exports = form
前端现有代码
Quiz.js
const finishQuiz = () => { if (Questions[currQuestion].answer === optionChosen) { setscore(score + 1); } setGameState("endScreen") // 待补充提交逻辑 }
现有finishQuiz函数会在答题结束时计算最终得分,并切换到结束屏,不确定是否需要在此处添加点击事件完成提交。
核心坑点
React的setState是异步批处理的,在调用setscore(score + 1)之后立刻读取score变量,拿到的还是更新前的旧值,直接用这个值发请求会导致提交的得分错误。
两种实现方案
方案1:答题完成自动提交
不需要额外绑定点击事件,算完最终得分直接发请求即可,修正后的代码如下:
const finishQuiz = () => { // 提前计算最终得分存入常量,避开state异步问题 const finalScore = Questions[currQuestion].answer === optionChosen ? score + 1 : score; // 更新页面展示用的得分state setscore(finalScore); setGameState("endScreen"); // 发送POST请求提交数据,将地址替换为你Postman测试时用的接口地址即可 fetch("/api/candidate", { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify({ fname: 你存储用户名的state变量, lname: 你存储用户姓氏的state变量, score: finalScore // 必须用提前算好的finalScore,不能直接用score变量 }) }) .then(res => res.json()) .then(res => { if(res.success) { console.log("得分提交成功") } else { console.error("提交失败:", res.message) } }) .catch(err => { console.error("请求异常:", err) }) }
如果项目用axios发起请求,替换fetch部分即可:
import axios from 'axios'; // 计算finalScore、更新state逻辑不变 axios.post("/api/candidate", { fname: 用户名变量, lname: 用户姓氏变量, score: finalScore }).then(res => { console.log("提交成功", res.data) }).catch(err => { console.error("提交失败", err) })
方案2:结束屏用户点击按钮后提交
如果需要用户确认得分后再手动提交,不需要在finishQuiz里写请求逻辑,步骤如下:
- 先修正
finishQuiz的得分计算逻辑,保证state中存储的得分正确:
const finishQuiz = () => { const finalScore = Questions[currQuestion].answer === optionChosen ? score + 1 : score; setscore(finalScore); setGameState("endScreen"); }
- 在结束屏的JSX中添加提交按钮,绑定提交事件:
{gameState === "endScreen" && ( <div className="end-screen"> <h2>测验完成,你的最终得分:{score}</h2> <button onClick={submitScore}>提交得分</button> </div> )}
- 实现
submitScore提交函数,此时state中的score已经是更新后的最终值,可以直接使用:
const submitScore = () => { fetch("/api/candidate", { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify({ fname: 用户名变量, lname: 用户姓氏变量, score: score }) }) .then(res => res.json()) .then(res => { if(res.success) { alert("得分提交成功!") } else { alert("提交失败,请重试") } }) .catch(err => { alert("网络异常,请重试") }) }
注意事项
- 接口地址和你Postman测试时用的地址保持一致即可
- 如果接口需要登录鉴权,在请求headers中添加对应的token字段
fname、lname字段替换为你实际存储用户姓名的变量即可,如果没有收集姓名可以传空字符串,或者直接在后端模型里调整这两个字段的必填规则
内容的提问来源于stack exchange,提问作者Darkpsinight
相关产品推荐
相关产品推荐

