React useEffect首次刷新正常,二次刷新后money/luck重置问题求助
问题:刷新两次后
money和luck被重置为默认值 首次刷新时代码运行正常,但刷新两次后,money和luck会被重置为默认值1和10。代码逻辑为:通过第一个useEffect获取用户数据并设置状态;第二个useEffect在money或luck变化时将数据推送至API同步到数据库。
用户提供代码:
const [luck, setLuck] = useState(1); const [money, setMoney] = useState(10); useEffect(() => { const getUser = async () => { const res = await fetch(`/api/email/${session?.user?.email}`, { method: "GET", headers: { "Content-Type": "application/json", Authorization: "tmthisdumb123", }, }); const data = await res.json(); setName(data.name); setLuck(data.luck); setEmail(data.email); setMoney(data.money); if (data.rarity && data.quality && data.rarity !== "Unknown") { setRarity(data.rarity); setQuality(data.quality); setLevel(data.level); setMold(data.mold); setEnchant1(data.enchant1); setEnchant2(data.enchant2); setEnchant3(data.enchant3); setEnchantName1(data.enchantName1); setEnchantName2(data.enchantName2); setEnchantName3(data.enchantName3); setID(data.swordId); setValue( CalculateRarityValue(data.rarity) * CalculateQualityValue(data.quality) * CalculateMoldValue(data.mold) * (CalculateLevelValue(data.level) * 7.5) * CalculateEnchant(data.enchant1) * CalculateEnchant(data.enchant2) * CalculateEnchant(data.enchant3) * EnchantPower(data.enchant1) * EnchantPower(data.enchant2) * EnchantPower(data.enchant3) * CalculateRaritySuffix(data.rarity) * 20 ); setSold(false); setGeneratable(true); } return { user: data }; }; getUser(); }, []); // Save the users data everytime luck or money changes const saveUser = async () => { await fetch(`/api/email/${session?.user?.email}`, { method: "POST", headers: { "Content-Type": "application/json", Authorization: "tmthisdumb123", }, body: JSON.stringify({ luck: luck, money: money, }), }); }; useEffect(() => { saveUser(); }, [money, luck]);
问题原因
组件初始化时,useState先设置luck=1、money=10的默认值,此时第二个useEffect会直接触发saveUser,在第一个useEffect完成真实数据获取前就把默认值同步到了数据库。第一次刷新时,API返回的真实数据会覆盖默认值,所以看起来正常;但第二次刷新时,数据库里已经被默认值覆盖,获取到的就是错误数据,最终显示默认值。
解决方案
1. 增加加载状态,避免初始值触发保存
添加isLoaded状态标记数据是否加载完成,仅在加载完成后执行保存操作:
const [luck, setLuck] = useState(1); const [money, setMoney] = useState(10); const [isLoaded, setIsLoaded] = useState(false); // 新增加载状态 useEffect(() => { const getUser = async () => { const res = await fetch(`/api/email/${session?.user?.email}`, { method: "GET", headers: { "Content-Type": "application/json", Authorization: "tmthisdumb123", }, }); const data = await res.json(); setName(data.name); setLuck(data.luck); setEmail(data.email); setMoney(data.money); // ... 其他状态设置代码 setIsLoaded(true); // 数据加载完成后标记 }; getUser(); }, []); const saveUser = async () => { if (!isLoaded) return; // 未加载完成时不执行保存 await fetch(`/api/email/${session?.user?.email}`, { method: "POST", headers: { "Content-Type": "application/json", Authorization: "tmthisdumb123", }, body: JSON.stringify({ luck: luck, money: money, }), }); }; useEffect(() => { saveUser(); }, [money, luck, isLoaded]); // 依赖项添加isLoaded
2. 优化请求触发时机(可选)
如果session在组件挂载时可能未就绪,把session?.user?.email加入第一个useEffect的依赖项,确保用户信息就绪后再发起请求:
useEffect(() => { if (!session?.user?.email) return; // 无用户邮箱时不发起请求 const getUser = async () => { // ... 原有请求代码 }; getUser(); }, [session?.user?.email]); // 添加session依赖
3. 后端增加校验(可选)
在后端处理保存请求时,校验传入的money/luck是否合理,或者仅支持基于当前数据库数据的增量更新,避免前端错误值直接覆盖真实数据。
内容的提问来源于stack exchange,提问作者FSCYT
相关产品推荐
相关产品推荐

