Javascript 如何使用React钩子使React门户工作?

Javascript 如何使用React钩子使React门户工作?,javascript,reactjs,react-hooks,Javascript,Reactjs,React Hooks,我特别需要在浏览器中收听自定义事件,我有一个按钮可以打开一个弹出窗口。我目前正在使用React门户打开另一个窗口(PopupWindow),但当我在其中使用钩子时,它不起作用——但如果我使用类,它就会起作用。通过工作,我的意思是,当窗口打开时,两个窗口都显示其下方的div,但当事件中的数据刷新时,带有挂钩的窗口会将其删除。要进行测试,请将车窗打开至少5秒钟 我在CodeSandbox中有一个例子,但我也会在这里发布,以防网站关闭或其他情况: 下面的代码不会运行,因为我不知道如何通过react

我特别需要在浏览器中收听自定义事件,我有一个按钮可以打开一个弹出窗口。我目前正在使用React门户打开另一个窗口(PopupWindow),但当我在其中使用钩子时,它不起作用——但如果我使用类,它就会起作用。通过工作,我的意思是,当窗口打开时,两个窗口都显示其下方的div,但当事件中的数据刷新时,带有挂钩的窗口会将其删除。要进行测试,请将车窗打开至少5秒钟

我在CodeSandbox中有一个例子,但我也会在这里发布,以防网站关闭或其他情况:

下面的代码不会运行,因为我不知道如何通过react cdn使react钩子工作,但您现在可以使用上面的链接进行测试

const{useState,useffect}=React;
函数getRandom(最小值、最大值){
const first=Math.ceil(最小值)
最后常数=数学楼层(最大值)
返回Math.floor(Math.random()*(last-first+1))+first
}
函数replaceWithRandom(someData){
让newData={}
for(让d输入一些数据){
newData[d]=getRandom(someData[d],someData[d]+500)
}
返回新数据
}
const PopupWindowWithHooks=props=>{
const containerell=document.createElement('div')
让externalWindow=null
使用效果(
() => {
externalWindow=window.open(
'',
'',
`宽度=600,高度=400,左侧=200,顶部=200`
)
externalWindow.document.body.appendChild(containerell)
externalWindow.addEventListener('beforeunload',()=>{
props.closePopupUpfinowWithhooks()
})
console.log('创建的弹出窗口')
返回函数cleanup(){
console.log('已清理的弹出窗口')
externalWindow.close()
externalWindow=null
}
},
//仅当变量更改时才重新呈现此组件
[]
)
返回ReactDOM.createPortal(props.children,containerell)
}
类PopupWindow扩展了React.Component{
containerell=document.createElement('div')
externalWindow=null
componentDidMount(){
this.externalWindow=window.open(
'',
'',
`宽度=600,高度=400,左侧=200,顶部=200`
)
this.externalWindow.document.body.appendChild(this.containerell)
this.externalWindow.addEventListener('beforeunload',()=>{
this.props.closePopupWindow()
})
console.log('创建的弹出窗口')
}
组件将卸载(){
console.log('已清理的弹出窗口')
this.externalWindow.close()
}
render(){
返回ReactDOM.createPortal(
这个,道具,孩子们,
这是集装箱鱼
)
}
}
函数App(){
让数据={
大约600,
其他:200
}
让[dataState,setDataState]=useState(数据)
useffect(()=>{
let interval=setInterval(()=>{
setDataState(replaceWithRandom(dataState))
const event=new CustomEvent('onOverlayDataUpdate'{
详细信息:数据状态
})
文件。dispatchEvent(事件)
}, 5000)
返回函数clear(){
清除间隔(间隔)
}
}, [])
使用效果(
函数getData(){
document.addEventListener('onOverlayDataUpdate',e=>{
setDataState(如详细信息)
})
返回函数cleanup(){
document.removeEventListener(
“onOverlayDataUpdate”,
文件
)
}
},
[数据状态]
)
console.log(数据状态)
//状态处理
const[isPopupWindowOpen,setIsPopupWindowOpen]=useState(false)
常数[
isPopupWindowWithHooksOpen,
设置iPopupWithHooksopen
]=使用状态(false)
常量togglePopupWindow=()=>
setIsPopupWindowOpen(!isPopupWindowOpen)
const togglePopupWithhooks=()=>
setIsPopupWindowWithHooksOpen(!isPopupWindowWithHooksOpen)
const closePopupWindow=()=>setIsPopupWindowOpen(false)
const closePopupWindowWithHooks=()=>
setIsPopupWindowWithHooksOpen(假)
//副作用
useffect(()=>
window.addEventListener('beforeunload',()=>{
closePopupWindow()
closePopupWindowWithHooks()
})
)
返回(
切换窗口
用钩子拨动窗户
{isPopupWindowOpen&&(
这是怎么回事?
我应该一直在这里!
)}
{isPopupWindowWithHooksOpen&&(
这是怎么回事?
我应该一直在这里!
)}
)
}
const rootElement=document.getElementById('root'))
ReactDOM.render(,rootElement)

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

编辑

单击事件按钮,首先调用功能组件PopupUpIndowWithHooks的调用,它将按预期工作(在useEffect中创建新的
,将
附加到弹出窗口)

事件刷新,调用功能组件PopupWindowWithHooks的第二次调用,并再次行
const containerell=document.createElement('div')
创建新的
。但是(第二个)新的
将永远不会追加到弹出窗口中,因为行
externalWindow.document.body.appendChild(containerell)
正在使用,它将只在装载时运行,在卸载时清除(第二个参数是空数组[])

最后
返回ReactDOM.createPortal(props.children,containeerre)
使用第二个参数containeerre创建门户-新的未终止

使用Containerere作为有状态值(useState钩子),问题得到解决:

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


代码沙盒:

问题是:在每个渲染上创建一个新的div,只需在渲染外部创建div 功能和它应该按预期工作

const containerEl = document.createElement('div')
const PopupWindowWithHooks = props => {
   let externalWindow = null
   ... rest of your code ...

const门户=({children})=>{
const[modalContainer]=useState(document.createElement('div');
useffect(()=>{
//在DOM中查找根元素
乐
const App = () => (
  <Portal>
    <MyModal />
  </Portal>
)
import { useLayoutEffect, useRef } from "react";
import { createPortal } from "react-dom";

const useCreatePortalInBody = () => {
    const wrapperRef = useRef(null);
    if (wrapperRef.current === null && typeof document !== 'undefined') {
        const div = document.createElement('div');
        div.setAttribute('data-body-portal', '');
        wrapperRef.current = div;
    }
    useLayoutEffect(() => {
        const wrapper = wrapperRef.current;
        if (!wrapper || typeof document === 'undefined') {
            return;
        }
        document.body.appendChild(wrapper);
        return () => {
            document.body.removeChild(wrapper);
        }
    }, [])
    return (children => wrapperRef.current && createPortal(children, wrapperRef.current);
}
const Demo = () => {
    const createBodyPortal = useCreatePortalInBody();
    return createBodyPortal(
        <div style={{position: 'fixed', top: 0, left: 0}}>
            In body
        </div>
    );
}
import usePortal from 'react-useportal'

const App = () => {
  const { openPortal, closePortal, isOpen, Portal } = usePortal()
  return (
    <>
      <button onClick={openPortal}>
        Open Portal
      </button>
      {isOpen && (
        <Portal>
          <p>
            This is more advanced Portal. It handles its own state.{' '}
            <button onClick={closePortal}>Close me!</button>, hit ESC or
            click outside of me.
          </p>
        </Portal>
      )}
    </>
  )
}