如何在 React 和 Typescript 中全局存储 ref

How to store a ref globally in React & Typescript

某个组件我有很多实例,我们称它为<Item>。将鼠标悬停在任何 <Item> 上时,(quite 复杂且动态的)工具提示应出现在项目的位置。

因为我使用的是语义-ui-react,所以我选择的工具是使用Popup 来显示工具提示。使用弹出窗口的一种方法是给它们一个触发器组件(这将是我的 <Item>)和一个内容组件,它会自动显示在触发器组件周围的特定位置。但是后来我的每个项目都有一个 Popup 实例,这显着增加了我的应用程序的响应时间,因为即使我目前不需要它们,也必须创建所有 Popups。

另一种使用 Popup 的方法是通过 context 属性 给它一个 ref,它将在那个 DOM 节点打开。因此,我想使用这种机制只有一个 Popup,每当我将鼠标悬停在 <Item>.[=35= 上时,它将接收对其 context 属性 的动态更新]

不过,为此,我需要将当前 <Item> ref 传递给 Popup。因为我有一个深度嵌套的应用程序,所以我选择使用 https://github.com/diegohaz/constate 来全局共享状态。

不幸的是,共享 ref 似乎不起作用。每当我尝试从共享上下文中读取它时,它都是空的。

请看这里的简单示例: https://codesandbox.io/s/pplw689627

虽然我可以在调试器中看到 tooltipTarget 写入 onMouseEnter,但当它在 <Tooltip> 组件中读取时,它始终为 null。

知道我做错了什么吗?

我愿意接受不同的建议,但如果可能的话,我更愿意使用 Semantic 的 Popup 以保持一致的视觉风格。


更新:

Tom Finneys 的回答在上面的沙箱中有效,不幸的是我在我的实际环境中使用 Typescript 并且它不能立即工作。我在这个沙盒中得到了一个有效的解决方案: https://codesandbox.io/s/7143r32klj

主要问题是 RefObject<T>current 属性 是只读的。这可以防止您编写这样的上下文:

export function useTooltip() {
  const [tooltipRecipe, setTooltipRecipe] = React.useState<string | undefined>(
    undefined
  );
  let tooltipTarget = React.useRef<HTMLElement>(null);
  const setTooltipTarget = (target: HTMLElement | null) => {
    dummy.current = target;
  };
  return { tooltipRecipe, tooltipTarget, setTooltipRecipe, setTooltipTarget };
}

setTooltipTarget 无法编译。

我现在可以让它工作的唯一方法是将 RefObject<T> 强制转换为 current 不是只读的本地类型。这是 quite 一个黑客,但它有效。请参阅沙盒中的解决方案。


这里实际上正在围绕这个进行讨论: https://github.com/DefinitelyTyped/DefinitelyTyped/issues/31065

您的问题源于试图改变组件主体内部的 tooltipTarget 引用。您应该在您的上下文中声明另一个 setter 函数,您可以调用该函数来更改 ref.

的当前值

我在沙箱里查了一下:https://codesandbox.io/s/p6pknz837?fontsize=14