我在项目中使用了preact(react的小版本)。
在更新到preactX版本之前,我使用的是Modal组件,并且没有问题,这就是我的Modal组件的样子:
import { Component } from 'preact';
import Portal from 'preact-portal';
export default class Modal extends Component {
componentWillReceiveProps({ isOpen }) {
if (this.state.isOpen !== isOpen) {
this.setState({ isOpen });
}
}
handleClose = () => {
const { onClose } = this.props;
this.setState({ isOpen: false });
onClose && onClose();
};
render({ children, closeIcon, isOpen }) {
return isOpen && (
<Portal into="body">
<Wrapper className="notranslate">
<Overlay />
<Holder>
<Close onClick={this.handleClose}>
<img src={closeIcon || DefaultCloseIcon} alt="Close" />
</Close>
{children}
</Holder>
</Wrapper>
</Portal>
);
}
}
升级到preactX后,他们放弃了对Portal组件的支持,并将其更改为createPortal方法,就像在反应中那样,在这里发生问题的地方,只要props isOpen更改并且由于该模式多次打开,它就会呈现。 >
这是我使用钩子通过createPortal实现的模态组件的实现:
import { createPortal, useState, useEffect, memo } from 'preact/compat';
function Modal({ children, onCloseClick, closeIcon, isOpen }) {
const [isStateOpen, setIsStateOpen] = useState(isOpen);
useEffect(() => {
if (isStateOpen != isOpen) {
setIsStateOpen(isOpen);
}
return () => {
setIsStateOpen(false);
};
}, [isOpen]);
return (
isStateOpen &&
createPortal(
<Wrapper>
<Overlay />
<Holder>
<Close onClick={onCloseClick}>
<img src={closeIcon || DefaultCloseIcon} alt="Close" />
</Close>
{children}
</Holder>
</Wrapper>,
document.body
)
);
}
export default memo(Modal);
我正在使用像Modal这样的组件:
<App>
<SomeOtherComponents />
<Modal
isOpen={hasModalOpen}
closeIcon={CloseIcon}
onCloseClick={cancelModal}
>
<div>
some other content here
</div>
</Modal>
</App>
我使用Modal组件的地方可能会渲染多次,这也使Modal组件也渲染,这在我使用Portal之前是可以的,但是当我使用createPortal时,似乎createPortal无法识别Modal组件是否已经存在是否在dom。
我想反应也会发生同样的事情。
答案 0 :(得分:0)
这不是createPortal
问题,而是您对Hooks的使用。
我根据您发布的代码创建了一个演示,由于您的useEffect()
钩子返回了“ cleanup”回调,因此该演示不断进行重新渲染。该回调是不必要的,删除它可以修复整个演示:
https://codesandbox.io/s/preact-createportal-renders-multiple-times-32ehe
答案 1 :(得分:0)
我通过在Modal组件中添加shouldComponentUpdate方法解决了这个问题。
即使isOpen prop尚未更改,只要父项组件中的任何prop发生更改,该组件都将呈现。
shouldComponentUpdate(nextProps) {
return this.props.isOpen !== nextProps.isOpen;
}
似乎还因为老Portal在preactX之前的版本中应用了浅层渲染,所以createPortal并未应用浅层渲染