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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 09:55:21