如何在localStorage持久化所有点赞数据集,实现点赞切换效果
解决页面刷新后重复点赞问题的修改方案
核心问题分析
当前代码的关键缺陷是:
- 仅用单个
localStorage键存储单次点赞/取消请求的返回值,无法追踪所有已点赞的照片ID集合 - 组件初始化时未从
localStorage恢复之前的点赞状态 - 直接修改原数据数组和状态对象,违反React不可变状态更新原则
- 点赞数显示依赖
localStorage的孤立值,逻辑混乱
完整修改方案
1. 初始化时恢复点赞状态
将点赞状态与localStorage绑定,组件加载时自动读取历史点赞记录:
// 从localStorage读取已点赞照片集合,初始化组件状态 const [userLikedPhotos, setUserLikedPhotos] = useState(() => { const savedLikes = localStorage.getItem('userLikedPhotos'); return savedLikes ? JSON.parse(savedLikes) : {}; }); // 将gridData转为组件状态,避免直接修改原数据 const [photosData, setPhotosData] = useState(gridData);
2. 修正点赞/取消逻辑(遵循不可变原则)
更新状态时创建新对象/数组,同时同步更新localStorage:
const handleLikesBasedOnUserId = (likedPhotoUserId, userName) => { setUserLikedPhotos(prevState => { // 创建新的点赞状态对象 const newLikedState = {...prevState}; // 创建新的照片数据数组 const newPhotos = [...photosData]; const targetPhoto = newPhotos.find(photo => photo.UserID === likedPhotoUserId); if (newLikedState[likedPhotoUserId]) { // 取消点赞:移除ID,点赞数减1 delete newLikedState[likedPhotoUserId]; targetPhoto.likes -= 1; handleDislike(likedPhotoUserId, userName); } else { // 点赞:添加ID,点赞数加1 newLikedState[likedPhotoUserId] = true; targetPhoto.likes += 1; handleLike(likedPhotoUserId, userName); } // 持久化更新后的点赞集合 localStorage.setItem('userLikedPhotos', JSON.stringify(newLikedState)); // 更新照片数据状态 setPhotosData(newPhotos); return newLikedState; }); };
3. 调整API请求逻辑(移除无效的localStorage存储)
去掉单个请求的localStorage存储,仅保留API交互,添加请求失败回滚:
const handleLike = (likedPhotoUserId, userName) => { const url = 'http://127.0.0.1:8000/api/like'; const headers = { "Accept": 'application/json', "Authorization": `Bearer ${authToken}` }; axios.post(url, { UserID: likedPhotoUserId, userName, liked: true // 补全原代码未定义的liked变量 }, {headers}) .then(resp => console.log(resp.data)) .catch(err => { console.log(err); // API失败时回滚前端状态 setUserLikedPhotos(prev => { const newState = {...prev}; delete newState[likedPhotoUserId]; localStorage.setItem('userLikedPhotos', JSON.stringify(newState)); const newPhotos = [...photosData]; newPhotos.find(p => p.UserID === likedPhotoUserId).likes--; setPhotosData(newPhotos); return newState; }); }); }; const handleDislike = (likedPhotoUserId, userName) => { const url = 'http://127.0.0.1:8000/api/dislike'; const headers = { "Accept": 'application/json', "Authorization": `Bearer ${authToken}` }; axios.post(url, { UserID: likedPhotoUserId, userName, disliked: true // 补全原代码未定义的disliked变量 }, {headers}) .then(resp => console.log(resp.data)) .catch(err => { console.log(err); // API失败时回滚前端状态 setUserLikedPhotos(prev => { const newState = {...prev}; newState[likedPhotoUserId] = true; localStorage.setItem('userLikedPhotos', JSON.stringify(newState)); const newPhotos = [...photosData]; newPhotos.find(p => p.UserID === likedPhotoUserId).likes++; setPhotosData(newPhotos); return newState; }); }); };
4. 修正渲染逻辑(实时显示正确状态)
根据当前点赞状态动态调整按钮样式和文本,直接显示照片数据中的点赞数:
return ( <> {photosData.map((photo, index) => ( <div key={index}> <span className="likesAmt">❤️ {photo.likes}</span> <Button variant={userLikedPhotos[photo.UserID] ? "secondary" : "success"} onClick={() => handleLikesBasedOnUserId(photo.UserID, photo.name)} > {userLikedPhotos[photo.UserID] ? "Unlike" : "Like"} </Button> <br/> <span className="name"> {photo.name} {localStorage.getItem('UserID') === photo.UserID ? <h6 className="you">(You)</h6> : null} </span> </div> ))} </> );
修改后效果验证
- 点击点赞:点赞数+1,按钮变为"Unlike",
localStorage记录该照片ID - 刷新页面:组件自动读取
localStorage,按钮保持"Unlike"状态 - 再次点击:点赞数-1,按钮变回"Like",
localStorage移除该照片ID
内容的提问来源于stack exchange,提问作者sp92
相关产品推荐
相关产品推荐

