欢迎光临散文网 会员登陆 & 注册

React手册 Hooks 之 useRef

2023-05-23 14:07 作者:海里我最大  | 我要投稿

描述

    React 官网对 useRef 的描述原文

    useRef is a React Hook that lets you reference a value that’s not needed for rendering.

useRef 是一个 React Hook 可以让你引用到一个不需要渲染的值.

      useRef 是一个不太常用的 hook, React 认为 useRef 是一个应急方案(escape hatch), 与 useState 很类似, 都是维护一个 hook 变量, 区别在与 useState 维护的变量是用做视图更新, 而 useRef 是维护了一个普通的 JS 容器变量.


场景

    使用 useRef 的场景, 一般是需要与外部 API 通信的时候, 而且这些 API 大多不会影响到组件外观, 如果你的组件需要存储一些值, 但不会影响渲染逻辑, 请选择 ref, React 官方列举了一些出现频率较高的情况:

  • 存储 timeout ID

  • 存储和操作 DOM 元素

  • 存储不需要被用来计算 JSX 的其他对象

    接口定义:


参数           

  • initialValue: any

    useRef 返回的 Ref 对象的 current 属性的初始值, 可以是任意类型, 只有在组件首次渲染时才会有效, 后续渲染会使用缓存中的对象引用.

返回

  • Ref: { current: T }

    返回一个对象引用, current 初始值是传入的 initialValue 之所以是一个对象, 因为 React 必须维护到一个对象引用, 才能保证你获取的是同一个对象, 而且还可以满足一个任意类型的业务数据, 所以这个格式是必须的, 作为调用者只能操作 Ref.current 属性, 如果你将 ref 对象作为一个 JSX 节点的 ref 属性传给 React , 那么 React 会把 current 属性赋值为一个 DOM 对象.

用法1

    使用 useRef 引用一个值, 在后续渲染中, useRef 会返回相同的对象, 这个对象上有一个 current 属性, 用来存储数据, 修改 current 并不会导致重新渲染.

    你可以在后续的操作中读取这个对象, 但请不要在渲染期间读取, 如果一定要在渲染期间写入读取, 请使用 state 代替, 因为 state 至少是可预测的, 如果使用不恰当 React 会做出提示.


用法2

    避免重复计算 ref 初始值, 虽然 useRef 的初始值只在初次渲染时使用, 但是如果是像下面这样通过调用函数返回的结果, 那么在后续渲染中, 虽然结果会被丢弃, 但是函数依然会被调用, 这可能会造成浪费.

    虽然在渲染期间不允许读取和写入 ref.current, 但是在下面这种情况下是可以的, 因为这样实际的效果也只会在首次执行, 是可预测的, 并且避免了初始化方法 getTestRef 的调用浪费.


用法3

    通过 ref 操作 DOM, 这是 useRef 使用最多的一种用法, 首先声明一个初始值为 nullref 对象, 然后将 ref 对象通过 ref 属性传递给想要操作的 DOM 节点的 JSX.

    当 React 创建 DOM 并渲染时, 会将 DOM 节点赋值给传入的 ref 对象的 current 属性, 当 DOM 节点被移除时, React 会把 current 的值设置成 null.


用法4

    获取自定义组件的 ref, 如果你直接在自定义组件上增加 ref 属性, 会得到一个错误  

    这是 React 故意的, Refs 是紧急方案, 应该谨慎使用, 直接暴露 DOM 节点信息会让代码变的脆弱, 因此当父组件想要获取子组件的 DOM 时, 必须子组件同意并通过 forwardRef 暴露出指定 DOM 节点给外界. 

     上面例子中 Children 通过 forwardRef 暴露了一个 input 元素, 父元素 MyApp 可以调用到 input.focus 方法, 同时父组件也能做其他的事情, 比如删除插入元素等一些子组件不希望产生但无法阻止的事情, 这个时候, 可以使用 useImperativeHandle 限制父组件获取到的 ref 对象.

    使用了 useImperativeHandle 之后, 父组件的 ref 获取到的就不再是子组件的 DOM, 而是一个子组件指定的 JS 对象, 这样对子组件来说就保证了安全.


总结

  • useRef 是一个应急方案, 大多数时候不应该是首选, 与 useState 类似都是存储一个变量, 区别在于 useRef 的返回值不会引起重新渲染;

  • useRef 接收一个任意类型的参数, 只有在首次渲染有用, 后续渲染会丢弃, 返回一个含有 current 字段的对象, 默认值是传入 useRef 的参数, current 的值可变, 但是不应该在渲染过程中读取和写入;

  • 渲染过程中可以使用 testRef.current === null 判断来限制修改 ref.current, 这种操作是允许的;

  • 通过 JSX 节点上的 ref 属性, 可以让 ReactDOM 赋值给 ref.current, 但是不能在子组件上直接使用;

  • 要获取子组件 DOM 需要通过 forwardRef 方法包装子组件, 并报漏一个 DOM 节点给父组件.

  • 如果子组件不想报漏 DOM 节点, 那么可以使用 useImperativeHandle 来指定传递一个任意值给父组件的 ref 接收.


React手册 Hooks 之 useRef的评论 (共 条)

分享到微博请遵守国家法律