React状态更新不符合预期,后端未识别请求体值问题
问题描述
我有一个React组件,会根据状态和按钮点击条件设置值,通过RTK Query把数据对象传给后端控制器,现在遇到两个问题:
- 控制台日志显示状态值和预期相反:提交状态为true时,点击「取消提交」应该把状态设为false、两个字符串清空,但实际传的是旧值;提交状态为false时,点击「提交报告」应该把状态设为true并填充字符串,实际还是传旧值。
- Mongoose/Express控制器不根据
req.body的值响应,始终返回旧数据。
React组件代码
const Submit = ({ planId, plan, user, today}) => { const [isSubmitted, setIsSubmitted] = useState(plan.submitted); const [submitBy, setSubmitBy] = useState(plan.submittedBy); const [submitDate, setSubmitDate] = useState(plan.submittedDate); const [skip, setSkip] = useState(true) const [userId, setUserId] = useState() const [updateStatus] = useUpdateReportStatusMutation() const {data} = useGetUserQuery(userId, {skip}) useEffect(() => { if(isSubmitted) { setUserId(plan.submittedBy), setSkip(false) } }, [isSubmitted]) const onSubmit= async (data) => { console.log('onSubmit: ', data) //This shows the data as reflected by the onClick functions try { const payload = await updateStatus({ planId, data }).unwrap(); console.log('fulfilled', payload) //continues to show the same already existing data } catch (err) { console.error('Failed to update report status: ', err) } toast.success("Report Status Updated", { position: toast.POSITION.TOP_RIGHT }); } const handleUnsubmitValues = () => { setIsSubmitted(false) setSubmitBy('') setSubmitDate( '') console.log("values for unsubmit: ", isSubmitted, submitBy, submitDate) //this is currently logging- isSubmitted: true, submitBy: 'the users ID', submitDate: 'an ISO date string' handleSubmit() } const handleSubmitValues = () => { setIsSubmitted(true) setSubmitBy(user) setSubmitDate(today) console.log("values for submit", isSubmitted, submitBy, submitDate) //this is logging- isSubmitted: false, submitBy: '', submitDate: '' handleSubmit() } const handleSubmit = () => { const data = { submitted: isSubmitted, submittedBy: submitBy, submittedDate: submitDate } console.log("before submit", data) //this logs the same values as the function call onSubmit(data) } const subDate = new Date(plan.submittedDate).toLocaleDateString() return ( <> {isSubmitted ? ( <> <CheckBoxIcon /> <label>{data?.fullName}</label><br /> <label>{subDate}</label><br /> <Button color='warning' variant='contained' onClick={handleUnsubmitValues}>Unsubmit</Button> </> ) : <> <CheckBoxOutlineBlankIcon /> <Button color='primary' variant='contained' onClick={handleSubmitValues}>Submit Report</Button> </> } <br /> </> ) }
Mongoose/Express控制器代码
exports.updateReportStatus = async (req, res) => { console.log("req.body", req.body) //logs the values as supplied by the onSubmit try { const servicePlan = await ServicePlan.findOne({ _id: req.params.planId }) if (req.body.submitted) { servicePlan.submitted = req.body.submitted } if (req.body.submittedBy) { servicePlan.submittedBy = req.body.submittedBy; } if (req.body.submittedDate) { servicePlan.submittedDate = req.body.submittedDate } if (req.body.approved) { servicePlan.approved = req.body.approved } if (req.body.approvedBy) { servicePlan.approvedBy = req.body.approvedBy; } if (req.body.approvedDate) { servicePlan.approvedDate = req.body.approvedDate } if (req.body.sent) { servicePlan.sent = req.body.sent } if (req.body.sentBy) { servicePlan.sentBy = req.body.sentBy; } if (req.body.sentTo) { servicePlan.sentTo = req.body.sentTo } if (req.body.sentDate) { servicePlan.sentDate = req.body.sentDate } console.log("status ", servicePlan) //logs the same existing values, regardless of req.body servicePlan.save() res.send(servicePlan) } catch (error) { res.status(404) res.send({ error: "Error updating report status", error}) } }
控制台日志
提交操作(预期为true及填充字符串)
values for submit false <empty string> <empty string> before submit Object { submitted: false, submittedBy: "", submittedDate: "" } onSubmit: Object { submitted: false, submittedBy: "", submittedDate: "" }
取消提交操作(预期为false及空字符串)
values for unsubmit: true 62410a1dcaac9a3d0528de7a 2022-09-15T15:55:27.758Z before submit Object { submitted: true, submittedBy: "62410a1dcaac9a3d0528de7a", submittedDate: "2022-09-15T15:55:27.758Z" } onSubmit: Object { submitted: true, submittedBy: "62410a1dcaac9a3d0528de7a", submittedDate: "2022-09-15T15:55:27.758Z" }
解决方案
前端问题:异步状态更新导致旧值提交
React的useState更新是异步的,调用setIsSubmitted等方法后立刻执行handleSubmit,此时状态还未完成更新,所以拿到的是旧值。不需要依赖组件状态构造提交数据,直接在点击函数里生成预期的提交对象:
const handleUnsubmitValues = () => { // 直接构造提交数据 const submitData = { submitted: false, submittedBy: '', submittedDate: '' }; // 更新本地状态 setIsSubmitted(false); setSubmitBy(''); setSubmitDate(''); // 提交数据 onSubmit(submitData); }; const handleSubmitValues = () => { const submitData = { submitted: true, submittedBy: user, submittedDate: today }; setIsSubmitted(true); setSubmitBy(user); setSubmitDate(today); onSubmit(submitData); };
同时可以删除handleSubmit函数,避免从状态取值的延迟问题。
后端问题:Mongoose更新逻辑错误
原代码的条件判断会忽略false、空字符串这类“假值”,导致无法更新对应字段。需要判断字段是否存在于req.body中,而非字段值的真假;另外save()是异步操作,必须加await确保保存完成后再返回数据:
exports.updateReportStatus = async (req, res) => { console.log("req.body", req.body); try { const servicePlan = await ServicePlan.findOne({ _id: req.params.planId }); // 判断字段是否存在,而非值的真假 if ('submitted' in req.body) { servicePlan.submitted = req.body.submitted; } if ('submittedBy' in req.body) { servicePlan.submittedBy = req.body.submittedBy; } if ('submittedDate' in req.body) { servicePlan.submittedDate = req.body.submittedDate; } // 其他字段同理修改 if ('approved' in req.body) { servicePlan.approved = req.body.approved; } if ('approvedBy' in req.body) { servicePlan.approvedBy = req.body.approvedBy; } if ('approvedDate' in req.body) { servicePlan.approvedDate = req.body.approvedDate; } if ('sent' in req.body) { servicePlan.sent = req.body.sent; } if ('sentBy' in req.body) { servicePlan.sentBy = req.body.sentBy; } if ('sentTo' in req.body) { servicePlan.sentTo = req.body.sentTo; } if ('sentDate' in req.body) { servicePlan.sentDate = req.body.sentDate; } console.log("status ", servicePlan); // 等待保存完成 await servicePlan.save(); res.send(servicePlan); } catch (error) { res.status(404).send({ error: "Error updating report status", error }); } };
内容的提问来源于stack exchange,提问作者Jowz
相关产品推荐
相关产品推荐

