preact createPortal 渲染多次
preact createPortal renders multiple times
我在我的项目中使用了 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 方法,就像 react 中的方法一样,这里发生问题的地方,只要 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);
我正在使用这样的模态组件:
<App>
<SomeOtherComponents />
<Modal
isOpen={hasModalOpen}
closeIcon={CloseIcon}
onCloseClick={cancelModal}
>
<div>
some other content here
</div>
</Modal>
</App>
我使用 Modal 组件的地方可能会渲染多次,这也会导致 Modal 组件渲染,这在我使用 Portal 之前很好,但是当我使用 createPortal 时,createPortal 似乎无法识别 Modal 组件是否存在已经在dom or not.
我想同样的事情也会发生在反应中。
这不是 createPortal
问题,而是您对 Hooks 的使用。
我根据您发布的代码创建了一个演示,由于从您的 useEffect()
挂钩返回的 "cleanup" 回调,它一直在重新呈现。该回调是不必要的,删除它可以修复整个演示:
https://codesandbox.io/s/preact-createportal-renders-multiple-times-32ehe
我通过在 Modal 组件中添加 shouldComponentUpdate 方法解决了这个问题。
似乎只要父组件中的任何 prop 发生变化,即使 isOpen prop 没有改变,组件也会渲染。
shouldComponentUpdate(nextProps) {
return this.props.isOpen !== nextProps.isOpen;
}
createPortal 似乎也没有应用浅层渲染,因为旧的 Portal 在 preactX
之前的版本中应用了它
我在我的项目中使用了 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 方法,就像 react 中的方法一样,这里发生问题的地方,只要 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);
我正在使用这样的模态组件:
<App>
<SomeOtherComponents />
<Modal
isOpen={hasModalOpen}
closeIcon={CloseIcon}
onCloseClick={cancelModal}
>
<div>
some other content here
</div>
</Modal>
</App>
我使用 Modal 组件的地方可能会渲染多次,这也会导致 Modal 组件渲染,这在我使用 Portal 之前很好,但是当我使用 createPortal 时,createPortal 似乎无法识别 Modal 组件是否存在已经在dom or not.
我想同样的事情也会发生在反应中。
这不是 createPortal
问题,而是您对 Hooks 的使用。
我根据您发布的代码创建了一个演示,由于从您的 useEffect()
挂钩返回的 "cleanup" 回调,它一直在重新呈现。该回调是不必要的,删除它可以修复整个演示:
https://codesandbox.io/s/preact-createportal-renders-multiple-times-32ehe
我通过在 Modal 组件中添加 shouldComponentUpdate 方法解决了这个问题。
似乎只要父组件中的任何 prop 发生变化,即使 isOpen prop 没有改变,组件也会渲染。
shouldComponentUpdate(nextProps) {
return this.props.isOpen !== nextProps.isOpen;
}
createPortal 似乎也没有应用浅层渲染,因为旧的 Portal 在 preactX
之前的版本中应用了它