preact createPortal渲染多次

时间:2020-05-16 17:30:42

标签: javascript reactjs preact

我在项目中使用了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。

我想反应也会发生同样的事情。

2 个答案:

答案 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并未应用浅层渲染