在TS中,React如何使用ref获取子组件的Dom结构?

前言

最近在业务开发时,突然遇到一个关于TS的业务问题。这个具体业务是:首先有个一个父容器,父容器内有三个子容器,点击分页按钮,让父容器滚动到对应子容器模块。 这个我们就涉及到了一个问题:由于要考虑到不同屏幕的适配问题,父容器滚动的距离需要根据子容器的高度来确定,所以我们需要获取到子容器的高度。

当时第一时间我没有将子容器分成组件来实现,所以我们直接使用Ref就很容易的拿到了子容器的高度。实现了该功能。但由于父容器的代码量越来越大,我就将子容器分成子组件开发。这是当我再去使用Ref实现时,TS就开始报如下的错误了。

这时问题就来了:

  • 在JS中我们可以如何获取到子组件的Dom结构呢?
  • 在TS中我们又该在JS的基础上添加那些东西才可以获取到子组件的Dom结构呢?
  • 为什么需要添加这些东西呢?

JS如何使用?

首先我们来解决第一个问题:在JS中,父子组件是怎么使用ref的?

我先准备好父组件,关键代码如下:

javascript 复制代码
function App() {
  const [height, setHeight] = useState(0)
  const childRef = useRef(null)
  const getHeight = () => {
    console.log(childRef.current.clientHeight);
    setHeight(childRef.current.clientHeight)
  }
  return (
    <div>
      <Child ref={childRef}></Child>
      <button onClick={getHeight}>获取子容器的高度:{height}</button>
    </div>
  )
}

父组件准备完了,我们再看看子组件代码:

javascript 复制代码
const  Child = forwardRef((props, ref) => { // 这个ref就是
  return (
    <div ref={ref} style={{height: '50vh', width: '100%'}}>
        这是子容器
    </div>
  )
})

接下来我们就来看看上述两份代码是怎么实现, 首先我们需要用forwardRef, 它是React中用于在函数组件中获取对另一个组件的引用的API, 它帮我们绝解决的问题是组件引用时用,并循环嵌套或组件嵌套过深的问题。 它允许我们在组件函数中获取对另一个组件的引用, 并将这个引用作为参数传递给组件。 这样我们再在子组件上绑定一个ref属性,通过forwardRef传给了父组件,这样父组件就可以拿到子组件的Dom结构。

TS如何使用?

上面我们看完了JS的实现,那接下来我们就该看看TS版啦。如果我们直接把JS代码搬到TS上,我们来看看会有什么效果?

它报了上述两个ts的类型错误。那我们就需要给他们加上类型,代码如下:

javascript 复制代码
function App() {
  const [height, setHeight] = useState<number>(0)
  const childRef = useRef<HTMLDivElement>(null)
  const getHeight = () => {
    console.log(childRef.current!.clientHeight);
    setHeight(childRef.current!.clientHeight)
  }
  return (
    <div>
      <Child ref={childRef}></Child>
      <button onClick={getHeight}>获取子容器的高度:{height}</button>
    </div>
  )
}
javascript 复制代码
const  Child = forwardRef((props, ref:ForwardedRef<HTMLDivElement>) => {
  return (
    <div ref={ref} style={{height: '50vh', width: '100%'}}>
        这是子容器
    </div>
  )
})

如上述代码所示,我们给他加上了两个类型,分别是ForwardedRef<HTMLDivElement> 和 <HTMLDivElement>,我们就解决了第一个类型错误, 我们再给childRef.current加上一个断言,我们就解决了第二个错误。我们也就实现了如下的效果。

为什么?

我们来看看这两个东西是什么:

  • HTMLDivElement: 在 TypeScript 中,HTMLDivElement 是一个类型声明(type declaration),用于表示 HTML DOM 中的 <div> 元素。通过使用 HTMLDivElement 类型,你可以在 TypeScript 代码中明确指定某个变量、函数参数、返回值等的类型为 <div> 元素。
  • ForwardedRef: 在 TypeScript 中,ForwardedRef 是一个泛型类型,用于定义一个转发引用。它通常用于在组件中将 ref 属性传递给子组件,以便对子组件的引用进行操作。我们通过使用 ForwardedRef 将 ref 进行转发,确保正确地传递ref。

相比于JS,TS给了我们更多的类型限制,在上述代码中,不难看出我们根本没有修改逻辑问题,只是通过TS来限定了类型。所以在TS项目中,我们每写一个东西都要考虑类型的问题,这样我们才可以避免出错。

相关推荐
LucianaiB3 小时前
【元宝搜索开发者征文大赛】AI时代,学得慢就不用学?用元宝搜索打造一个教程保质期,确保每一个教程符合你的现状
前端·人工智能·ai编程
excel3 小时前
JavaScript 对象池:减少高频对象创建与 GC 压力
前端
陈随易5 小时前
纯 Go 写的 JS 引擎,跑分超过了 C 语言的 QuickJS
前端·后端·程序员
子兮曰7 小时前
Chrome 权限元素实战:144 与 151 的渐进增强写法
前端·javascript·chrome
IT_陈寒7 小时前
Redis连接池泄漏那次,我差点把生产环境搞崩了
前端·人工智能·后端
强尼银手7 小时前
我花一天做了个格斗游戏原型,判定全对,然后被「美术」劝退了
前端·javascript
石小石Orz7 小时前
AI 正在蚕食我们的编码能力
前端·后端·算法
陈随易8 小时前
专注飞机 FocusFlight,两个人把番茄钟做成了一趟航班
前端·后端·程序员
总要学点什么8 小时前
第98篇:三维特效-材质线效果——给一条线换十种材质,虚线的图案只填了一半
开发语言·前端·javascript·ecmascript·gis·webgl·材质
10share8 小时前
基于大模型的 i18n 方案:把中文原文当 Key,轻松搞定多语言维护
前端·vue.js