React+MongoDB按钮仅首次点击更新数据库问题排查与修复
问题描述
作为React和MongoDB新手,尝试给MongoDB数据库中的用户有效期日期增加月份,但只有首次点击<Price>按钮时数据库会更新,后续点击无效,必须登出再重新登录才能再次更新(仍仅生效一次)。
问题原因
- 后端更新无精准定位:
updateActiveDate控制器中,User.updateOne({ $set: { activeUntil: req.body.activeUntil } })没有指定查询条件,会更新所有用户的有效期,而非当前登录用户;后续点击时数据库重复执行无效更新,前端也无法获取正确的用户最新数据。 - 前端用户状态未同步:
AuthContext中的user数据是登录时的缓存值,每次点击都基于旧的activeUntil计算新日期,导致请求参数错误;同时dateFormat不是React状态,页面显示无法自动更新。 - 异步请求未等待完成:
updateDate函数中调用axios.put时未加await,reFetch可能在更新请求完成前执行,无法获取最新数据。
修复方案
1. 修复后端更新控制器(精准更新当前用户)
修改updateActiveDate,通过URL参数中的namekey定位目标用户,更新后返回最新用户数据供前端同步:
import User from "../models/User.js"; export const updateActiveDate = async (req, res, next) => { try { // 按namekey定位当前用户,仅更新目标用户 await User.updateOne( { namekey: req.params.namekey }, { $set: { activeUntil: req.body.activeUntil } } ); // 返回更新后的用户数据,用于前端同步状态 const updatedUser = await User.findOne({ namekey: req.params.namekey }); res.status(200).json(updatedUser); } catch (err) { next(err); } };
2. 修复前端组件逻辑
将dateFormat改为React状态,等待更新请求完成后同步用户状态:
import React, { useContext, useState, useEffect } from "react"; import useFetch from "../../hooks/useFetch"; import Footer from "../../components/Footer"; import Navbar from "../../components/Navbar"; import Sidebar from "../../components/Sidebar"; import { ContractContainer, HeadingContainer, TypeH1, ActiveUntil, MonthlyWrapper, MonthlyContainer, MonthNumber, Price, Navbarback, } from "./userinfoElements"; import { AuthContext } from "../../context/AuthContext"; import moment from "moment"; import axios from "axios"; const Userinfo = () => { const [isOpen, setIsOpen] = useState(false); const { user, dispatch } = useContext(AuthContext); // 将dateFormat改为React状态,确保页面响应更新 const [dateFormat, setDateFormat] = useState(""); const { data, loading } = useFetch(`/contracts/${user.contractType}`); // 初始化或用户状态变化时同步日期显示 useEffect(() => { if (user?.activeUntil) { setDateFormat(moment(user.activeUntil).format("DD/MMMM/yyyy")); } }, [user]); const toggle = () => { setIsOpen(!isOpen); }; const updateDate = async () => { try { // 基于最新的用户状态计算新日期 const newDate = moment(user.activeUntil).add(1, "months"); // 等待更新请求完成,获取后端返回的最新用户数据 const res = await axios.put(`/activedate/${user.namekey}`, { activeUntil: newDate, }); // 更新AuthContext中的用户状态,确保后续计算用最新值 dispatch({ type: "LOGIN_SUCCESS", payload: res.data, }); // 更新页面显示的日期 setDateFormat(newDate.format("DD/MMMM/yyyy")); } catch (err) { console.log(err); } }; return ( <> <Sidebar isOpen={isOpen} toggle={toggle} /> <Navbar toggle={toggle} /> <Navbarback /> {loading ? ( "Loading components, please wait" ) : ( <> <ContractContainer> <HeadingContainer> <TypeH1>{data.contractType}</TypeH1> <ActiveUntil>Subscription active until {dateFormat}</ActiveUntil> </HeadingContainer> <MonthlyWrapper> <MonthlyContainer> <MonthNumber>1 Month</MonthNumber> <Price onClick={updateDate}>{data.month1Price}$</Price> </MonthlyContainer> <MonthlyContainer> <MonthNumber>3 Month</MonthNumber> <Price onClick={updateDate}>{data.month3Price}$</Price> </MonthlyContainer> <MonthlyContainer> <MonthNumber>6Month</MonthNumber> <Price onClick={updateDate}>{data.month6Price}$</Price> </MonthlyContainer> <MonthlyContainer> <MonthNumber>12Month</MonthNumber> <Price onClick={updateDate}>{data.month12Price}$</Price> </MonthlyContainer> </MonthlyWrapper> </ContractContainer> </> )} <Footer /> </> ); }; export default Userinfo;
内容的提问来源于stack exchange,提问作者Mega Animenia
相关产品推荐
相关产品推荐

