首页 > 解决方案 > 使用 useEffect 时反应 createPortal 未触发

问题描述

我有模态组件,但它根本没有呈现。我试图找出问题,但我似乎无法找到答案。

这是我的代码:

export default React.memo(function DialogComponent({
  children,
  className,
  closeModal,
  extraOptionClassName,
  title,
  visible,
  ...attributes
}: Props) {
  let modalRoot: HTMLElement;

  modalRoot = document.getElementById('MainGrid_row1');
  if (!modalRoot) {
    modalRoot = document.getElementById('MainGrid');
  }
  if (modalRoot == null) {
    modalRoot = document.createElement('div');
    console.log(modalRoot);
  }

  const el: HTMLElement = document.createElement('div');
  el.classList.add('c-dialog');

  useEffect(() => {
    if (el && modalRoot) {
      modalRoot.appendChild(el);
    }
    return () => {
      if (el && modalRoot && modalRoot.contains(el)) {
        modalRoot.removeChild(el);
      }
    };
  }, [el]);

  return createPortal(
    <div
      {...attributes}
      className={cx(
        'c-dialog',
        {
          'c-dialog': visible,
          'c-dialog--hidden': !visible,
        },
        className,
        `c-dialog--${extraOptionClassName}`
      )}
    >
      <div
        className={`c-dialog__modal-window c-dialog__modal-window${
          !visible ? '--hidden' : '--visible'
        }`}
        onClick={() => closeModal()}
      >
        <div
          className="c-dialog__window"
          onClick={e => {
            e.stopPropagation();
          }}
        >
          <div className="c-dialog__top-wrapper">
            <div className="c-dialog__close">
              <div className="c-dialog__x-logo" onClick={() => closeModal()}>
                {crossIconSelect}
              </div>
            </div>
          </div>
          <Item>{children}</Item>
        </div>
      </div>
    </div>,
    el
  );
});

return createPortal 未触发或返回。这里可能是什么问题?我可以看到 useEffect 工作正常。我正在使用故事书 UI 组件资源管理器

谢谢您的帮助

沙箱:https ://codesandbox.io/s/cranky-gagarin-fhsoc?file=/src/App.tsx

标签: reactjs

解决方案


主要问题是您忘记将新创建的 Div 插入正文中;所以它只是在记忆中。

同样在每次组件重新渲染时,它都会在代码中重新创建el元素;我不认为你想要什么。

export default React.memo(function DialogComponent({
  children,
  className,
  closeModal,
  extraOptionClassName,
  title,
  visible,
  ...attributes
}: Props) {
  // no need for all that boilerplate code.
  const modalRoot = document.getElementById('MainGrid_row1') || document.getElementById('MainGrid');



  useEffect(() => {

    // YOU NEED TO INSERT THIS DIV SOMEWHERE
    // newly createdElement is just in memory in your code. add it to body for example
    // remember its immutable; you can append el to it later it will work;
    if (!modalRoot) {
      modalRoot = document.createElement('div');
      document.body.append(modalRoot);
      console.log(modalRoot);
    }
    
    // el will change on ever render if outside. move it inside useEffect
    const el: HTMLElement = document.createElement('div');
    el.classList.add('c-dialog');
    modalRoot.appendChild(el);
    
    return () => {
        document.removeChild(modalRoot);
    };
  }, []);

  return createPortal( ... rest of your code ... )

推荐阅读