我有一个在浏览器中监听自定义事件的特定需求,然后我有一个按钮可以打开一个弹出窗口。我目前正在使用 React Portal 打开另一个窗口(PopupWindow),但是当我在里面使用钩子时它不起作用 - 但如果我使用类就可以工作。通过工作,我的意思是,当窗口打开时,两者都显示其下方的 div,但带有钩子的 div 在事件数据刷新时将其擦除。要进行测试,请将窗口打开至少 5 秒钟。
我在 CodeSandbox 中有一个例子,但我也会在这里发布以防网站关闭或其他原因:
https://codesandbox.io/s/k20poxz2j7
下面的代码将无法运行,因为我不知道如何通过 react cdn 使 react hooks 工作,但您现在可以使用上面的链接对其进行测试
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="https://unpkg.com/react@16.7.0-alpha.2/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16.7.0-alpha.2/umd/react-dom.development.js"></script>
<div id="root"></div>