React Hook——useRef 的使用
使用 useState、useReducer、useContext 创建的状态,都是可读不可变的,一旦更新就会触发组件的重新渲染。但是实际开发过程中你经常需要一些不希望引起组件重新渲染的状态、并且希望在组件的生命周期中,该状态能被一直保持在 React 中。
Refs 就是为了解决这个问题提出来的。
当你需要在组件中一直缓存一些状态,但是并不想因为这些状态的改变而重新触发渲染,那么你可以选择使用 ref。
使用示例:
- 当你点击
button的时候,会发现页面并没有更新countRef.current最新值,但是控制台中的countRef.current确每次会更新变化 useRef会给你返回一个带有current属性的对象,你可以通过ref.current访问当前值。useRef与useState返回的状态不同之处就是:ref.current的值是可读可变的,你可以直接通过ref.current = newValue,进行更改。- 并且更改
useRef不会触发组件的重新渲染,这是因为react没有对ref的值进行track操作。
如果使用 useState:
- 点击
button会重新渲染,可以看到变化,这是因为React会跟踪state
通常我们会在哪种情况下使用 useRef:
- 当你需要操作
DOM的时候,可以使用ref保持对DOM的引用 - 当你需要使用计时器时,可以保持对计时器的引用,以保证在恰当的时机可以重置计时器
- 当你需要记录一些不影响组件重新渲染的状态时。
操作 DOM
在业务需求中,经常会遇到操作 DOM 的场景,比如:滚动视图到指定位置、表单获取焦点、移动 DOM 位置、调整 DOM 大小等等。这种情况下就可以使用 useRef 钩子去保存对 DOM 对象的引用。
引用的方式一般分为两种:
- 直接引用组件自身的
DOM对象 - 引用子组件的
DOM对象
1. 引用组件自身的 DOM 对象
- 通过给
HTML标签绑定一个ref属性,来实现DOM引用
2. 访问子组件的 DOM 节点
- 需要从
React中导出forwardRefAPI,将子组件传递给forwardRef - 父组件将 ref 变量 传递给子组件,子组件绑定 ref 属性至目标标签
最佳实践
- 将
refs作为react的一个逃生舱。当你需要调用 React 外部系统或者浏览器的一些原生API的时候,refs是非常有用的。但是当你的组件中有很多逻辑和数据流需要依赖ref的值时,你需要重新思考你的编码方式。 - 在**渲染时(rendering 阶段)**读取或者更改
ref的值,如果有些信息需要在渲染时用到,则使用state代替,因为 React 不知道 ref.current 何时会发生改变。在渲染时依赖 ref.current 会使你的组件行为无法预测。 React对state的限制不会作用于refs。例如***state的行为在每次渲染时更像是一张快照并且不会同步更新***。但是ref的值是同步立即改变的。因为ref本身是一个常规类型的JavaScript Object
当你使用 ref 时不必担心如何避免状态变化。只要你没有在渲染阶段使用可变的 ref 就行。React 并不关心你在 ref.current 上做的任何操作。
refs vs state
- 返回值不同:
useRef钩子返回的是一个带有current属性的常规JavaScript对象,可读可变useState钩子返回的是一个数组,数组第一项状态可读不可变,只能通过第二项去更改状态
Track情况不同:refs的值不会被 React 跟踪,所以改变refs不会触发重新渲染state是每次改变都会触发重新渲染
- 可保存的值些许不同:
- 相较于
useState钩子,useRef可以用于保存对DOM的引用。
- 相较于
React 何时更新 refs
在 React 中,每次更新会分为两个阶段:
- 渲染期间,
React会调用组件函数计算出哪些内容应该渲染到视图上 commit期间,React会将计算出来的DOM更新到真实的DOM上
通常情况下,你不想在渲染过程中访问 refs。这也适用于持有 DOM 节点的 ref。在第一次渲染期间,DOM 节点还没有创建,因此 ref.current 将为 null。在渲染更新阶段,DOM 节点还没有更新。所以在渲染更新过程中读取还为时过早。
React 在会在 commit 阶段设置 ref.current。在更新 DOM 之前,React 将受影响的 ref.current 值设置为 null。更新 DOM 之后,React 立即将它们设置为相应的 DOM 节点。
总结
Refs用来保存不用于渲染期间的值。Refs是一个常规JavaScript对象,它只有一个名为current的属性,你可以读取或设置该属性。- 你可以通过调用
useRef钩子要求React给你一个引用。 - 与状态一样,
Refs允许你在组件重新渲染之间保留信息。 - 与
state不同,设置ref的当前值不会触发重新呈现。 - 不要在渲染期间读或写
ref.current。这使得你的组件行为难以预测。
转载自:https://juejin.cn/post/7171779499715985439