渲染SweetAlert时出现React已渲染状态下无法刷新更新警告如何解决
报错原因
这个unstable_flushDiscreteUpdates警告的本质是React执行渲染流程的同时,有其他同步状态更新被触发,导致React无法正常处理离散更新队列,你的代码存在3个直接诱因:
- Formik的render props回调参数和外层
LoginOverlay的入参都命名为props,造成作用域污染,同时SweetAlert的html属性直接读取Formik的实时values,Formik状态更新触发重渲染时如果刚好切换SweetAlert的显隐状态,会同步触发SweetAlert内部的DOM/状态更新,和当前渲染流程冲突 - 同步重定向逻辑直接写在JSX返回中,
<Redirect>组件渲染时会同步触发路由状态更新,此时如果刚好SweetAlert也在切换显隐,就会触发更新嵌套 - 两个SweetAlert组件都放在Formik的render回调内部,Formik的任意状态变化都会触发这两个组件的props重新计算,旧版本的SweetAlert React封装库内部状态更新没有用副作用包装,会直接在渲染阶段触发更新
解决方案
按顺序执行以下修改即可:
- 修复命名冲突,避免作用域污染
把Formik的render props回调参数改名,所有Formik内部属性用新名称调用:
// 原代码 {(props) => ( // 修改为 {(formikProps) => ( // 后续所有Formik属性调用同步改为formikProps.xxx,比如formikProps.getFieldProps、formikProps.values.email
- 把重定向逻辑移到副作用中,避免渲染时同步触发路由更新
新增useEffect处理重定向,删除原有JSX中的<Redirect>代码段:
useEffect(() => { if (localStorage.getItem("did_token") || magic.entity?.loggedIn) { history.push('/business/home') } }, [magic.entity?.loggedIn, history])
- 把SweetAlert组件移出Formik的render回调
将两个SweetAlert放到LoginOverlay的根返回节点下,减少不必要的重渲染触发,修改后代码结构如下:
const LoginOverlay = (props) => { const history = useHistory(); const { magic, login, clearError } = props; // 新增的重定向逻辑 useEffect(() => { if (localStorage.getItem("did_token") || magic.entity?.loggedIn) { history.push('/business/home') } }, [magic.entity?.loggedIn, history]) return ( <> <Formik // 原有Formik配置保持不变 {(formikProps) => ( <div className="app-wrapper min-vh-100 bg-white"> {/* 原有布局、表单代码全部保持不变,删除里面的SweetAlert、Redirect代码段 */} </div> )} </Formik> {/* 两个SweetAlert移到此处 */} <SweetAlert title="Check your email" show={!magic.entity?.loggedIn && magic.showInfoDialog} html={`We emailed a magic link to ${formikProps.values.email}</br>Click the link in your email and then return to this tab to log in or sign up.</br>`} type="info" showCancelButton={false} showConfirmButton={false} /> <SweetAlert title="Error" show={!magic.entity?.loggedIn && magic.errorMessage} html={magic.errorMessage} type="error" showCancelButton={false} showConfirmButton={true} onConfirm={() => clearError()} /> </> ) }
- 若修改后仍有警告,给SweetAlert的显隐状态加微任务延迟,避免和父组件渲染同步
新增state控制SweetAlert显隐,用useEffect + 0延迟定时器更新状态,把更新操作放到下一个事件循环执行:
const [showInfoAlert, setShowInfoAlert] = useState(false) const [showErrorAlert, setShowErrorAlert] = useState(false) useEffect(() => { setTimeout(() => { setShowInfoAlert(!magic.entity?.loggedIn && magic.showInfoDialog) setShowErrorAlert(!magic.entity?.loggedIn && !!magic.errorMessage) }, 0) }, [magic.entity?.loggedIn, magic.showInfoDialog, magic.errorMessage])
再把SweetAlert的show属性替换为对应的state即可。
内容的提问来源于stack exchange,提问作者1977
相关产品推荐
相关产品推荐

