如何将 React useRef 钩子与打字稿一起使用?

Posted

技术标签:

【中文标题】如何将 React useRef 钩子与打字稿一起使用?【英文标题】:How to use React useRef hook with typescript? 【发布时间】:2019-06-22 13:32:56 【问题描述】:

我正在使用新的 useRef 挂钩创建引用

const anchorEl = React.useRef<htmlDivElement>(null)

并使用like

<div style= width: "15%", ...flexer, justifyContent: "flex-end" >
    <Popover
        id="simple-popper"
        open=open
        anchorEl=anchorEl
        onClose=() => 
          setOpen(false)
        
        anchorOrigin=
          vertical: 'bottom',
          horizontal: 'center',
        
        transformOrigin=
          vertical: 'top',
          horizontal: 'center',
        
    >
        <Typography>The content of the Popover.</Typography>
    </Popover>
</div>
<div ref=anchorEl >
      ...

但我收到此错误

TS2322: Type 'MutableRefObject<HTMLDivElement>' is not assignable to type 'HTMLElement | ((element: HTMLElement) => HTMLElement)'.
  Type 'MutableRefObject<HTMLDivElement>' is not assignable to type '(element: HTMLElement) => HTMLElement'.
    Type 'MutableRefObject<HTMLDivElement>' provides no match for the signature '(element: HTMLElement): HTMLElement'.
Version: typescript 3.2.2, tslint 5.12.0

【问题讨论】:

【参考方案1】:

anchorEl 变量是 ref 对象,一个只有current 属性的对象。未知 Popover 是如何工作的,但它需要一个元素作为 anchorEl 道具,而不是参考。

应该是:

<Popover
    id="simple-popper"
    open=open
    anchorEl=anchorEl.current

如果&lt;Popover&lt;div ref=anchorEl &gt; 是如图所示的兄弟姐妹,则在作为道具传递时,引用将无法使用。在这种情况下,组件需要在挂载时重新渲染:

const [, forceUpdate] = useState(null);

useEffect(() => 
  forceUpdate();
, []);

...

    anchorEl.current && <Popover
        id="simple-popper"
        open=open
        anchorEl=anchorEl.current
        ...
   
   <div ref=anchorEl >

如果&lt;div ref=anchorEl &gt; 不必渲染到 DOM,它可以是

   <Popover
        id="simple-popper"
        open=open
        anchorEl=<div/>

渲染一个组件两次并使用forceUpdate 解决方法的必要性表明这可以以更好的方式完成。这里的实际问题是Popover 接受一个元素作为道具,而接受 refs 在 React 中很常见。

此时 ref 对象没有任何好处。 Ref callback 可以与 useState 一起使用,状态更新函数是接收新状态作为参数的回调,如果它接收到相同的状态(DOM 元素),它不会导致额外的更新:

const [anchorEl, setAnchorEl] = useState<HTMLDivElement>(null);

...

    anchorEl && <Popover
        id="simple-popper"
        open=open
        anchorEl=anchorEl
        ...
   
   <div ref=setAnchorEl >

【讨论】:

很好的答案。在 TypeScript 中,您必须将值传递给 forceUpdate。我使用了 null。 很高兴它有帮助。是的,这是有道理的。请注意,null 或根本没有 arg(未定义)仅在这种特定情况下有效,以在挂载时强制更新状态一次,对于多次强制更新,需要像 这样的新状态,请参阅 ***.com/a/53215514/3731501 您是否必须编写丑陋的反应才能克服打字稿编译问题?? @ThanasisIoannidis 你能澄清一下吗?该问题有编译错误,因为代码中有错误。建议进行修复。 JS 也是一样。 @EstusFlask 我认为使用anchorEl.current 作为useEffect 中的依赖项可以做得更好,并在此useEffect 中将状态设置为anchorEl.current 的值。这将触发隐式重新渲染,而无需强制执行。我的观点是,它看起来不像是 hack

以上是关于如何将 React useRef 钩子与打字稿一起使用?的主要内容,如果未能解决你的问题,请参考以下文章

React hook useRef 不适用于样式化组件和打字稿

将 react-redux useSelector 与打字稿一起使用

打字稿:React Native useRef 给出错误“对象可能为空”

尝试在打字稿中使用 React useref 时出错

在自定义输入元素上使用带有打字稿的 useRef

如何在打字稿中使用 react-navigation 的 withNavigation?