Reactjs 当底层组件重新渲染时,为什么popper会跳到左上角?

Reactjs 当底层组件重新渲染时,为什么popper会跳到左上角?,reactjs,material-ui,use-effect,popper.js,slate.js,Reactjs,Material Ui,Use Effect,Popper.js,Slate.js,我正在使用MaterialUIPopper组件(它反过来使用Popper.js)创建一个悬停工具栏。除了一个奇怪的行为外,它在大多数情况下运行良好: 选择一些文本:悬停工具栏显示在文本上方-如预期的那样 选择工具栏中的任意按钮:执行相应的操作。但是,工具栏会跳到窗口的左上角。见下文 您可以在中尝试此行为-只需选择一些文本并单击其中一个“T”按钮 基本问题围绕提升器的定位: 当用户选择一些文本时,将创建一个伪虚拟元素,并将其作为锚元素传递给popper。Popper使用此anchorEl定位悬停

我正在使用MaterialUIPopper组件(它反过来使用Popper.js)创建一个悬停工具栏。除了一个奇怪的行为外,它在大多数情况下运行良好:

  • 选择一些文本:悬停工具栏显示在文本上方-如预期的那样
  • 选择工具栏中的任意按钮:执行相应的操作。但是,工具栏会跳到窗口的左上角。见下文
  • 您可以在中尝试此行为-只需选择一些文本并单击其中一个“T”按钮

    基本问题围绕提升器的定位:

  • 当用户选择一些文本时,将创建一个伪虚拟元素,并将其作为锚元素传递给popper。Popper使用此
    anchorEl
    定位悬停工具栏。到目前为止还不错
  • 当用户单击工具栏中的按钮时,悬停工具栏会跳到窗口的左上角
  • 我猜这是因为当底层组件重新渲染时,锚元素不知何故丢失了。我不知道为什么,但这只是我的理论。有人能帮我解决这个问题吗

    计算主播的代码位于React
    useffect()
    中。我已确保
    useffect
    的依赖项列表是准确的。我可以看到,当工具栏跳转时,
    useffect()
    没有被调用,这意味着
    ancorel
    没有被重新计算。这让我相信工具栏应该在当前位置保持不变,而不是跳转到(0,0)。但事实并非如此:-(

    以下是工具栏组件中的
    useffect()
    代码。您可以在中找到完整的代码。如有任何帮助,将不胜感激

    useEffect(() => {
        if (editMode === 'toolbar') {
            if (isTextSelected) {
                const domSelection = window.getSelection();
                if (domSelection === null || domSelection.rangeCount === 0) {
                    return;
                }
                const domRange = domSelection.getRangeAt(0);
                const rect = domRange.getBoundingClientRect();
                setAnchorEl({
                    clientWidth: rect.width,
                    clientHeight: rect.height,
                    getBoundingClientRect: () =>
                        domRange.getBoundingClientRect(),
                });
                setToolbarOpen(true);
            } else {
                setToolbarOpen(false);
            }
        } else {
            setToolbarOpen(false);
        }
    }, [editMode, isTextSelected, selection, selectionStr]);
    

    我相信您的
    domRange
    在完成其工作后不再有效(因为dom节点被替换),因此
    getBoundingClientRect
    不再返回任何有意义的内容

    您应该能够通过在主播的
    getBoundingClientRect
    中重新获取范围来修复此问题。可能类似于以下内容(我没有尝试执行它,因此不能保证没有小错误):


    你搞定了,瑞恩!现在很有魅力。非常感谢!
    const getSelectionRange = () => {
      const domSelection = window.getSelection();
      if (domSelection === null || domSelection.rangeCount === 0) {
        return null;
      }
      return domSelection.getRangeAt(0);
    };
    useEffect(() => {
      if (editMode === "toolbar") {
        if (isTextSelected) {
          const domRange = getSelectionRange();
          if (domRange === null) {
            return;
          }
          const rect = domRange.getBoundingClientRect();
          setAnchorEl({
            clientWidth: rect.width,
            clientHeight: rect.height,
            getBoundingClientRect: () => {
              const innerDomRange = getSelectionRange();
              return innerDomRange === null
                ? null
                : innerDomRange.getBoundingClientRect();
            }
          });
          setToolbarOpen(true);
        } else {
          setToolbarOpen(false);
        }
      } else {
        setToolbarOpen(false);
      }
    }, [editMode, isTextSelected, selection, selectionStr]);