【问题标题】:React Modal and Tooltip issue when using Portal使用 Portal 时出现 React Modal 和 Tooltip 问题
【发布时间】:2021-11-19 21:45:33
【问题描述】:

我有一个简单的 Modal 组件和一个简单的 Tooltip 组件。两者都可以通过点击触发按钮打开并通过点击外部关闭。为了检测外部点击,我使用了这个简单的钩子:

const useClickAway = (
  ref: Ref,
  condition: boolean,
  handler: Handler
): void => {

  useEffect(() => {
    const listener = (e: Event) => {
      if (!ref.current || ref.current.contains(e.target as Node)) {
        return;
      }
      handler(e);
    };
    if (condition) {
      document.addEventListener('mouseup', listener);
      document.addEventListener('touchend', listener);
    }
    return () => {
        document.removeEventListener('mouseup', listener);
        document.removeEventListener('touchend', listener);
    };
  }, [ref, handler, condition]);
};

这就是我使用它的方式:

/*
* ref - reference to the modal container
* isOpen - The modal state.
* handleClose - Handler that closes the modal.
*/
useClickAway(ref, isOpen, handleClose)

到目前为止它工作正常,但是当我尝试在此 Modal 内渲染我的工具提示(使用 Portal 将其渲染到 body 元素中,而不是反应树)时出现了问题。

当我打开模态然后打开其中的工具提示时,单击工具提示会导致模态关闭。因为点击工具提示被认为是点击了模态框的外部。

谁能为这个问题提供干净的解决方案?

【问题讨论】:

    标签: reactjs modal-dialog click tooltip portal


    【解决方案1】:

    我相信您可以利用 forwardRef 传递在 Modal Tooltip 共享父级中定义的 ref

    我会这样做:

    首先,我将重写TooltipModal 以接受可选的外部属性ref。如:

    const Tooltip = React.forwardRef((props, ref) => {
      const tooltipLocalRef = useRef(null);
      const tooltipRef = ref || tooltipLocalRef;
    
      //
    });
    
    // usage:
    const tooltipRef = useRef(null);
    <Tooltip ref={tooltipRef} anotherProps={someValue} />
    

    Modal 组件也是如此,但是除了我们将用于 Modal 本身的 ref 之外,我们还将发送 tooltipRef 作为额外的 prop。

    
    const tooltipRef = useRef(null);
    const modalRef = useRef(null);
    
    
    <Tooltip ref={tooltipRef} anotherProp={someValue} />
    <Modal ref={modalRef} tooltipRef={tooltipRef} anotherProp={someValue} />
    

    通过这样做,我相信我们可以检查模式外的点击,并在该目标位于 tooltipRef.current 节点内时例外。

    模态handleClose处理程序的额外工作:

    function handleClose(e) {
          if (!props.tooltipRef.current || props.tooltipRef.current.contains(e.target as Node)) {
            return;
          }
          setModalOpen(false)
    }
    

    我还没有测试过,让我知道结果如何。

    【讨论】:

    • 感谢@Sultan H. 的回答。我明白你在说什么,应该可以正常工作,但我不喜欢这个解决方案。如果我想在 Modal 中渲染例如菜单或类似的东西,我将不得不添加另一个 ref 并创建另一个例外以使其正常工作。
    • 我将等待更清洁的解决方案,如果没有出现任何问题,我将在工具提示包装元素上使用 event.stopPropagation()。
    • 你说得对,我诚实地使用e.stopPropagtion,到目前为止它并没有引起任何正常现象。我拥有的模态和工具提示组件也都使用 Portal 呈现。
    猜你喜欢
    • 2021-01-12
    • 1970-01-01
    • 2019-09-14
    • 2021-08-14
    • 2022-11-19
    • 2021-06-10
    • 2019-02-09
    • 2016-01-19
    • 2019-01-10
    相关资源
    最近更新 更多