如何使React Portal与React Hook一起使用?

编程入门 行业动态 更新时间:2024-10-25 08:26:38
本文介绍了如何使React Portal与React Hook一起使用?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧! 问题描述

我特别需要在浏览器中侦听自定义事件,从那里,我有一个可以打开弹出窗口的按钮.我目前正在使用React Portal打开另一个窗口(PopupWindow),但是当我在其中使用钩子时不起作用-但如果我使用类则可以.通过工作,我的意思是,当窗口打开时,两个窗口都显示其下方的div,但是当事件数据刷新时,带有钩子的窗口将擦除该div.要进行测试,请将窗口打开至少5秒钟.

I have this specific need to listen to a custom event in the browser and from there, I have a button that will open a popup window. I'm currently using React Portal to open this other window (PopupWindow), but when I use hooks inside it doesn't work - but works if I use classes. By working I mean, when the window opens, both shows the div below it but the one with hooks erases it when the data from the event refreshes. To test, leave the window open for at least 5 seconds.

我在CodeSandbox中有一个示例,但如果网站关闭或其他原因,我也会在此处发布:

I have an example in a CodeSandbox, but I'm also post here in case the website is down or something:

codesandbox.io/s/k20poxz2j7

下面的代码将无法运行,因为我不知道如何通过react cdn使react挂钩起作用,但是您现在可以使用上面的链接对其进行测试

const { useState, useEffect } = React; function getRandom(min, max) { const first = Math.ceil(min) const last = Math.floor(max) return Math.floor(Math.random() * (last - first + 1)) + first } function replaceWithRandom(someData) { let newData = {} for (let d in someData) { newData[d] = getRandom(someData[d], someData[d] + 500) } return newData } const PopupWindowWithHooks = props => { const containerEl = document.createElement('div') let externalWindow = null useEffect( () => { externalWindow = window.open( '', '', `width=600,height=400,left=200,top=200` ) externalWindow.document.body.appendChild(containerEl) externalWindow.addEventListener('beforeunload', () => { props.closePopupWindowWithHooks() }) console.log('Created Popup Window') return function cleanup() { console.log('Cleaned up Popup Window') externalWindow.close() externalWindow = null } }, // Only re-renders this component if the variable changes [] ) return ReactDOM.createPortal(props.children, containerEl) } class PopupWindow extends React.Component { containerEl = document.createElement('div') externalWindow = null componentDidMount() { this.externalWindow = window.open( '', '', `width=600,height=400,left=200,top=200` ) this.externalWindow.document.body.appendChild(this.containerEl) this.externalWindow.addEventListener('beforeunload', () => { this.props.closePopupWindow() }) console.log('Created Popup Window') } componentWillUnmount() { console.log('Cleaned up Popup Window') this.externalWindow.close() } render() { return ReactDOM.createPortal( this.props.children, this.containerEl ) } } function App() { let data = { something: 600, other: 200 } let [dataState, setDataState] = useState(data) useEffect(() => { let interval = setInterval(() => { setDataState(replaceWithRandom(dataState)) const event = new CustomEvent('onOverlayDataUpdate', { detail: dataState }) document.dispatchEvent(event) }, 5000) return function clear() { clearInterval(interval) } }, []) useEffect( function getData() { document.addEventListener('onOverlayDataUpdate', e => { setDataState(e.detail) }) return function cleanup() { document.removeEventListener( 'onOverlayDataUpdate', document ) } }, [dataState] ) console.log(dataState) // State handling const [isPopupWindowOpen, setIsPopupWindowOpen] = useState(false) const [ isPopupWindowWithHooksOpen, setIsPopupWindowWithHooksOpen ] = useState(false) const togglePopupWindow = () => setIsPopupWindowOpen(!isPopupWindowOpen) const togglePopupWindowWithHooks = () => setIsPopupWindowWithHooksOpen(!isPopupWindowWithHooksOpen) const closePopupWindow = () => setIsPopupWindowOpen(false) const closePopupWindowWithHooks = () => setIsPopupWindowWithHooksOpen(false) // Side Effect useEffect(() => window.addEventListener('beforeunload', () => { closePopupWindow() closePopupWindowWithHooks() }) ) return ( <div> <button type="buton" onClick={togglePopupWindow}> Toggle Window </button> <button type="buton" onClick={togglePopupWindowWithHooks}> Toggle Window With Hooks </button> {isPopupWindowOpen && ( <PopupWindow closePopupWindow={closePopupWindow}> <div>What is going on here?</div> <div>I should be here always!</div> </PopupWindow> )} {isPopupWindowWithHooksOpen && ( <PopupWindowWithHooks closePopupWindowWithHooks={closePopupWindowWithHooks} > <div>What is going on here?</div> <div>I should be here always!</div> </PopupWindowWithHooks> )} </div> ) } const rootElement = document.getElementById('root') ReactDOM.render(<App />, rootElement)

<script crossorigin src="unpkg/react@16.7.0-alpha.2/umd/react.development.js"></script> <script crossorigin src="unpkg/react-dom@16.7.0-alpha.2/umd/react-dom.development.js"></script> <div id="root"></div>

推荐答案

const [containerEl] = useState(document.createElement('div'));

编辑

按钮onClick事件,调用功能组件 PopupWindowWithHooks 的第一次调用,它按预期方式工作(在useEffect中创建新的< div> 将< div> 附加到弹出窗口).

Button onClick event, invoke first call of functional component PopupWindowWithHooks and it works as expected (create new <div>, in useEffect append <div> to popup window).

事件刷新,调用功能组件 PopupWindowWithHooks 的 second 调用,并在 const containerEl = document.createElement('div')行创建新再次< div> .但是,(第二个)新的< div> 永远不会追加到弹出窗口,因为 externalWindow.document.body.appendChild(containerEl)行在useEffect钩子中,该钩子会仅在mount上运行,然后在unmount上清除(第二个参数是一个空数组[]).

The event refresh, invoke second call of functional component PopupWindowWithHooks and line const containerEl = document.createElement('div') create new <div> again. But that (second) new <div> will never be appended to popup window, because line externalWindow.document.body.appendChild(containerEl) is in useEffect hook that would run only on mount and clean up on unmount (the second argument is an empty array []).

最后返回ReactDOM.createPortal(props.children,containerEl)创建带有第二个参数 containerEl 的门户-新的未附加的< div>

Finally return ReactDOM.createPortal(props.children, containerEl) create portal with second argument containerEl - new unappended <div>

使用 containerEl 作为有状态值(useState挂钩),问题得以解决:

With containerEl as a stateful value (useState hook), problem is solved:

const [containerEl] = useState(document.createElement('div'));

EDIT2

代码沙箱: codesandbox.io/s/l5j2zp89k9

更多推荐

如何使React Portal与React Hook一起使用?

本文发布于:2023-11-27 06:34:44,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1636982.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:React   Portal   Hook

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!