为什么我封装的PopUp弹窗HOC高阶组件无法正常工作?
问题原因
你现在的HOC用法完全错误。HOC每次调用都会返回一个独立的新组件,每个被包裹的组件都持有独立的内部状态,状态之间完全不互通。
你目前只给ButtonsOur按钮组件套了这个HOC,点击按钮时变更的active状态,是这个被包裹的按钮组件私有的状态,PopUpExc弹窗组件根本访问不到这个状态。就算你给弹窗也套一层同一个HOC,也会生成一份全新的独立active状态,和按钮那边的状态完全不同步,自然不会响应按钮的点击操作。
本质上你写的这个HOC只能给单个组件注入状态和方法,根本实现不了跨组件的状态共享。
修复方案
方案1:状态提升到公共父组件(优先推荐,符合React设计原则)
直接弃用当前的HOC,把弹窗开关状态、控制方法写在按钮和弹窗的共同父组件中,再通过props分别下发给两个组件即可,代码示例:
// 按钮与弹窗的公共父组件 function PageSection() { const [active, setActive] = useState(false); const openPop = () => setActive(true); const closePop = () => setActive(false); return ( <div> {/* 其他页面内容 */} <ButtonsOur open={openPop} /> <PopUpExc activevvv={active} close={closePop} /> </div> ) } // 按钮组件无需包裹HOC,直接接收props function ButtonsOur({ open }) { return ( <div className="base__routes__button"> <Buttons className="base__button__moreInf open-popup-exc" Click={open} >Докладніше</Buttons> <Buttons className="base__button__moreInf open-popup-exc" Click={open} >Забронювати</Buttons> </div> ) } // 弹窗组件无需包裹HOC,直接接收props function PopUpExc({activevvv, close}) { return ( <div className={activevvv ? "popup__bg__exc active" : "popup__bg__exc"} onClick={close} // 补充点击遮罩关闭弹窗的逻辑 > <div className="popup__exc" onClick={e => e.stopPropagation()}> <img onClick={close} src={Close} alt="close-popup" className="close-popup_exc" /> <div className="container"> <div className="row"> {/* 原有弹窗内容 */} </div> </div> </div> </div> ) }
方案2:改造HOC为组合式HOC,统一管理两个组件的状态
如果你一定要保留HOC的写法,可以改造HOC让它同时接收触发组件和弹窗组件,在HOC内部维护唯一的状态,再把对应props分发给两个组件,代码示例:
const withPopUpControl = (TriggerComponent, PopupComponent) => { const Controller = (restProps) => { const [active, setActive] = useState(false); const open = () => setActive(true); const close = () => setActive(false); useEffect(() => { console.log(active) }, [active]) return ( <> <TriggerComponent open={open} {...restProps.triggerProps} /> <PopupComponent activevvv={active} close={close} {...restProps.popupProps} /> </> ) } return Controller; } // 一次性传入按钮和弹窗组件,生成绑定好状态的组合组件 const BookPopUp = withPopUpControl(ButtonsOur, PopUpExc); // 使用时直接渲染组合组件即可 function Page() { return ( <div> {/* 其他页面内容 */} <BookPopUp /> </div> ) }
内容的提问来源于stack exchange,提问作者Anta
相关产品推荐
相关产品推荐

