React应用:点击关闭按钮后移除localStorage的redirect项,刷新后不再出现
React横幅关闭后localStorage的redirect项重复生成问题
问题场景
我在React应用里通过状态和localStorage控制横幅显示:
- 点击关闭按钮后,
showBanner状态存入localStorage,横幅不再展示; - 当带
redirect=my-site查询参数的页面被访问2次后,横幅自动隐藏。
目前代码功能正常,但存在一个问题:用户关闭横幅后,刷新页面时localStorage里的redirect项会重新生成,希望修复这个问题。
现有代码
import queryString from 'query-string'; const location = useLocation(); const queryParams = queryString.parse(location.search); const [showBanner, setShowBanner] = useState(true); const handleClick = () => { setShowBanner(false); localStorage.removeItem('redirect'); }; const hasQp = queryString .stringify(queryParams) .includes('redirect=my-site'); const initialCount = () => { if (typeof window !== 'undefined' && hasQp) { return Number(localStorage.getItem('redirect')) || 0; } return null; }; const [count, setCount] = useState(initialCount); const show = showBanner && hasQp && count! < 3; useEffect(() => { const data = localStorage.getItem('my-banner'); if (data !== null) { setShowBanner(JSON.parse(data)); } }, []); useEffect(() => { localStorage.setItem('my-banner', JSON.stringify(showBanner)); }, [showBanner]); useEffect(() => { let pageView = count; if (pageView === 0) { pageView = 1; } else { pageView = Number(pageView) + 1; } if (hasQp && showBanner === true) { localStorage.setItem('redirect', String(pageView)); setCount(pageView); } }, []);
问题根源
页面刷新时,最后一个空依赖的useEffect会优先执行,而此时showBanner的初始值是true(因为从localStorage读取my-banner的useEffect是异步触发的),导致判断条件hasQp && showBanner === true成立,重新生成了redirect项。
修复方案
核心修改点
- 直接在
useState初始化时读取showBanner:避免异步更新带来的判断偏差 - 给计数更新的
useEffect添加正确依赖:确保只有当横幅需要显示且存在目标查询参数时才更新计数 - 同步清理
redirect项:在showBanner变为false时,自动移除localStorage中的redirect,保证一致性
修改后的完整代码
import queryString from 'query-string'; const location = useLocation(); const queryParams = queryString.parse(location.search); // 初始化时直接从localStorage读取showBanner状态,无需异步useEffect const [showBanner, setShowBanner] = useState(() => { if (typeof window !== 'undefined') { const storedBannerState = localStorage.getItem('my-banner'); return storedBannerState ? JSON.parse(storedBannerState) : true; } return true; }); const handleClick = () => { setShowBanner(false); localStorage.removeItem('redirect'); }; // 简化查询参数判断,不用重新stringify const hasQp = queryParams.redirect === 'my-site'; const initialCount = () => { if (typeof window !== 'undefined' && hasQp && showBanner) { return Number(localStorage.getItem('redirect')) || 0; } return null; }; const [count, setCount] = useState(initialCount); const show = showBanner && hasQp && count < 3; useEffect(() => { localStorage.setItem('my-banner', JSON.stringify(showBanner)); // 当横幅关闭时,同步清理redirect项 if (!showBanner) { localStorage.removeItem('redirect'); } }, [showBanner]); useEffect(() => { // 只有横幅显示且存在目标查询参数时,才更新访问计数 if (!showBanner || !hasQp) return; const currentCount = count ?? 0; const newCount = currentCount + 1; localStorage.setItem('redirect', String(newCount)); setCount(newCount); }, [showBanner, hasQp, count]); // 添加必要依赖,确保状态变化时触发更新
额外优化建议
- 简化查询参数判断:原来的
queryString.stringify(queryParams).includes('redirect=my-site')效率低,直接用queryParams.redirect === 'my-site'更直接准确 - 类型安全处理:对
localStorage读取的redirect值增加类型校验,避免非数字值导致的逻辑错误 - 移除冗余代码:删除原来用于初始化
showBanner的空依赖useEffect,因为已经在useState初始化函数中完成了相同逻辑
内容的提问来源于stack exchange,提问作者meez
相关产品推荐
相关产品推荐

