React、NextJS与Redux的Local Storage数据刷新重置问题
问题分析与解决方案
核心问题
你遇到的LocalStorage刷新后重置,本质是Redux状态没有从LocalStorage恢复,反而用初始空值覆盖了存储的数据。原来的逻辑是把Redux状态同步到LocalStorage,但页面刷新后Redux回到初始状态,组件挂载时又把这个空值写回LocalStorage,直接冲掉了之前保存的内容。
修复步骤
1. 让Redux负责状态持久化
修改你的Redux Store配置,在初始化时从LocalStorage加载之前保存的状态,并监听状态变化自动同步到LocalStorage:
import { configureStore } from '@reduxjs/toolkit'; import userReducer from './userSlice'; // 从LocalStorage读取保存的用户状态 const loadSavedState = () => { try { const savedState = localStorage.getItem('userState'); return savedState ? JSON.parse(savedState) : undefined; } catch (err) { // 读取失败时用Reducer的初始状态 return undefined; } }; // 将状态同步到LocalStorage const saveStateToLocal = (state) => { try { // 只保存user切片的数据,避免冗余 const serializedState = JSON.stringify(state.user); localStorage.setItem('userState', serializedState); } catch (err) { // 忽略存储失败的情况 } }; const store = configureStore({ reducer: { user: userReducer, }, // 加载之前保存的状态作为初始值 preloadedState: { user: loadSavedState(), }, }); // 监听Redux状态变化,自动保存到LocalStorage store.subscribe(() => { saveStateToLocal(store.getState()); }); export default store;
2. 简化组件逻辑,移除冗余的useLocalStorage
组件只需要和Redux交互,不用直接操作LocalStorage,避免循环更新和覆盖数据:
export default function MyFunction() { const settings = { apiKey: API_KEY, network: Network.ETH_GOERLI }; const alchemy = new Alchemy(settings); const contractAddress = CONTRACT_ADDRESS; // 直接从Redux获取状态 const loggedIn = useSelector((state) => state.user.isLoggedIn); const owner = useSelector((state) => state.user.walletAddress); const nfts = useSelector((state) => state.user.nfts); const [pageContent, setPageContent] = useState("An error Occured"); const dispatch = useDispatch(); async function getNftsForOwner() { const _nfts = []; try { const nftsIterable = alchemy.nft.getNftsForOwnerIterator(owner); for await (const nft of nftsIterable) { if (nft.contract.address === contractAddress.toLowerCase()) { _nfts.push(nft); } } } catch (error) { console.log(error); } dispatch(setNfts(_nfts)); } async function signedHandler() { if (!window.ethereum) { setPageContent("Install Metamask in your browser"); } else { if (window.ethereum.isConnected()) { // 只有当Redux中nfts为空时才重新请求,避免重复调用API if (nfts.length === 0) { await getNftsForOwner(); } setPageContent( <div> <div><a>NFT Viewer</a></div> <div><a>Your NFT Collection :</a></div> <div><NftList nfts={nfts} /></div> </div> ); } else { setPageContent("Connect Wallet"); } } } useEffect(() => { signedHandler(); }, [loggedIn, owner, nfts]); return <div>{pageContent}</div>; }
关键注意点
- 确保你的Redux
userSlice的初始状态结构,和LocalStorage保存的结构一致,避免加载时出现数据不匹配的问题。 - 处理LocalStorage读写失败的场景(比如用户浏览器禁用了本地存储),这里用try/catch做了容错。
- 移除了原代码中
useEffect里的storeNft/storeOwner等依赖,避免循环触发更新导致的性能问题和数据覆盖。
内容的提问来源于stack exchange,提问作者Ryan Xavier
相关产品推荐
相关产品推荐

