React中localStorage存储延迟求助:游戏每日游玩限制功能异常
问题
我正在实现一项数据存储至当日午夜的功能,核心需求:
- 用户刷新页面后数据仍能保留
- 用户完成游戏后需次日才能进行新一轮游玩
目前遇到存储延迟问题:处理当前输入时,localStorage存储的总是上一次输入的数据,相关代码如下:
const compareInput = useCallback((inputValue) => { const guess = PLAYERS.find(player => player.playerName.toLowerCase() === inputValue.toLowerCase()); // console.log(guess); if(!guess) { alert("Player not found"); return; } if(guess.jerseyNumber === hero[0].jerseyNumber) { setplayer1((prevValues) => ({...prevValues, jerseyNumber: guess.jerseyNumber})); } if(guess.jerseyNumber === hero[1].jerseyNumber) { setplayer2((prevValues) => ({...prevValues, jerseyNumber: guess.jerseyNumber})); } if(guess.jerseyNumber === hero[2].jerseyNumber) { setplayer3((prevValues) => ({...prevValues, jerseyNumber: guess.jerseyNumber})); } if(guess.jerseyNumber === hero[3].jerseyNumber) { setplayer4((prevValues) => ({...prevValues, jerseyNumber: guess.jerseyNumber})); } if(guess.franchise === hero[0].franchise) { setplayer1((prevValues) => ({...prevValues, franchise: guess.franchise})); } if(guess.franchise === hero[1].franchise) { setplayer2((prevValues) => ({...prevValues, franchise: guess.franchise})); } if(guess.franchise === hero[2].franchise) { setplayer3((prevValues) => ({...prevValues, franchise: guess.franchise})); } if(guess.franchise === hero[3].franchise) { setplayer4((prevValues) => ({...prevValues, franchise: guess.franchise})); } if(guess.playerName === hero[0].playerName) { setplayer1((prevValues) => ({...prevValues, playerName: guess.playerName})); setGuessPlayer1(true); } if(guess.playerName === hero[1].playerName) { setplayer2((prevValues) => ({...prevValues, playerName: guess.playerName})); setGuessPlayer2(true); } if(guess.playerName === hero[2].playerName) { setplayer3((prevValues) => ({...prevValues, playerName: guess.playerName})); setGuessPlayer3(true); } if(guess.playerName === hero[3].playerName) { setplayer4((prevValues) => ({...prevValues, playerName: guess.playerName})); setGuessPlayer4(true); } localStorage.setItem('player1', JSON.stringify(player1)); localStorage.setItem('player2', JSON.stringify(player2)); localStorage.setItem('player3', JSON.stringify(player3)); localStorage.setItem('player4', JSON.stringify(player4)); }, [hero, inputValue, player1, player2, player3, player4]);
解决方案
问题根源
React的setState是异步操作,调用setplayer1这类方法后,player1的状态不会立即更新。你现在在调用setState后立刻执行localStorage.setItem,写入的自然是更新前的旧值,这就是存储延迟的原因。
修复方案
方案一:更新状态时同步写入localStorage
利用函数式更新的特性,在生成新状态的同时直接写入存储,确保存入的是最新值:
// 以更新player1的jerseyNumber为例 if(guess.jerseyNumber === hero[0].jerseyNumber) { setplayer1(prev => { const updatedPlayer1 = {...prev, jerseyNumber: guess.jerseyNumber}; localStorage.setItem('player1', JSON.stringify(updatedPlayer1)); return updatedPlayer1; }); }
对所有setplayerX的逻辑做同样修改,每个状态更新时同步写入对应的localStorage项。
方案二:用useEffect监听状态变化(更推荐)
移除compareInput里的localStorage写入代码,改用useEffect监听四个玩家状态的变化,状态更新时自动同步存储:
useEffect(() => { localStorage.setItem('player1', JSON.stringify(player1)); localStorage.setItem('player2', JSON.stringify(player2)); localStorage.setItem('player3', JSON.stringify(player3)); localStorage.setItem('player4', JSON.stringify(player4)); }, [player1, player2, player3, player4]);
这种方式更简洁,也符合React处理副作用的最佳实践,避免在事件回调里混杂状态更新和存储操作。
当日午夜过期逻辑实现
针对“数据保留至当日午夜”的需求,可以在存储时额外记录当前日期,读取时校验日期是否过期:
// 存储数据时同时记录当前日期 const saveGameData = () => { const today = new Date().toDateString(); localStorage.setItem('gameDate', today); // 写入玩家数据... }; // 页面初始化时校验日期 useEffect(() => { const savedDate = localStorage.getItem('gameDate'); const today = new Date().toDateString(); if(savedDate !== today) { // 日期过期,重置所有游戏数据 setplayer1(initialPlayerState); setplayer2(initialPlayerState); setplayer3(initialPlayerState); setplayer4(initialPlayerState); setGuessPlayer1(false); // ...重置其他游戏状态 // 清除过期的存储数据 localStorage.removeItem('player1'); localStorage.removeItem('player2'); localStorage.removeItem('player3'); localStorage.removeItem('player4'); localStorage.removeItem('gameDate'); } else { // 读取已存储的玩家数据恢复状态 const savedPlayer1 = JSON.parse(localStorage.getItem('player1')); if(savedPlayer1) setplayer1(savedPlayer1); // ...读取其他玩家数据 } }, []);
这样用户次日打开页面时,会自动重置游戏数据,满足“完成游戏后次日才能进行新一轮游玩”的要求。
内容的提问来源于stack exchange,提问作者user17031033
相关产品推荐
相关产品推荐

