React中使用LocalStorage控制Apple设备模态框不重复弹出报错问询
问题原因
你触发报错的核心原因是在组件的顶层渲染逻辑中直接调用了setOpen这个状态更新方法:
React组件每次状态更新都会触发重新渲染,你取消注释setOpen(false)后,执行逻辑就变成:组件渲染 → 调用setOpen更新状态 → 触发重新渲染 → 再次走到判断逻辑调用setOpen,陷入无限重渲染的死循环,最终触发报错。
修复方案
按照以下逻辑调整代码即可完全匹配需求:
- 初始化
open状态时直接从localStorage读取标记值,不需要额外在渲染过程中更新状态 - 把
localStorage的写操作放到用户关闭Modal的回调函数中,确保只有用户主动关闭后才会标记为不再弹出 - 删掉原来顶层直接操作状态和
localStorage的冗余逻辑
修复后完整代码
const MasterIndexPage = () => { const classes = useStyles() const [isAndroid, setIsAndroid] = useState(false) const [isApple, setIsApple] = useState(false) // 初始化时直接从localStorage判断是否要弹出:没标记过就弹出,标记过就不弹出 const [open, setOpen] = useState(() => { return localStorage.getItem('formModal') === null }) const handleClose = () => { setOpen(false) // 用户关闭时写入localStorage标记,后续不再弹出 localStorage.setItem('formModal', '1') } useEffect(() => { if (navigator.userAgent.match(/Android/i)) { setIsAndroid(true) } else if (navigator.userAgent.match(/iPhone|iPod|iPad/i)) { setIsApple(true) } }, []) return ( <> <h1>Hello</h1> <div> {isApple ? ( <Modal aria-labelledby="transition-modal-title" aria-describedby="transition-modal-description" className={classes.modal} open={open} onClose={handleClose} closeAfterTransition BackdropComponent={Backdrop} BackdropProps={{ timeout: 500, }} > <div id="popup"> <h4 className="h4_addtohome">Add my App!</h4> <p className="p__addtohome"> Tap below to add an icon to your home screen for quick access! </p> </div> </Modal> ) : null} </div> </> ) } export default MasterIndexPage
额外优化说明
- 原代码中return返回的多个根节点没有包裹,上面的代码用React Fragment(
<>)做了包裹,避免语法报错 - 去掉了无用的
userAgent、isWindows状态声明,减少冗余代码 localStorage存储的值统一用字符串类型,避免类型判断错误
内容的提问来源于stack exchange,提问作者Pinky Promise
相关产品推荐
相关产品推荐

