Escape Hatches 1: Refs
Referencing values with refs
When a piece of information is used for rendering, keep it in state. When a piece of information is only needed by event handlers and changing it doesn’t require a re-render, using a ref may be more efficient.
基本语法
import {
useRef } from 'react';.
const ref = useRef(0);
useRef
会返回一个类似如下的对象:
{
current: 0; // 传入 useRef 的初始值
}
可以通过 ref.current
获取当前ref的值,这个值是可变的,意味着你可以读取或写入它。React 不会跟踪 ref 的更新,即 ref.current
的值改变不会引发组件的重新渲染,这就是为什么 ref 可以作为 “Escape hatches” 的原因。
refs与state的区别
ref可以通过其 current 值来直接修改,但 state 需要通过对应的 setting function 才能修改。
下表是它们之间的区别:
refs | state |
---|---|
useRef(initialValue) 返回 { current: initialValue } |
useState(initialValue) 返回当前状态的值及其对应的 setting function ( [value, setValue] ) |
更改其值时不会引发重新渲染 | 每次更改时都会引发重新渲染 |
可变 - 你可以在渲染过程之外修改和更新 current 的值 |
“不可变” - 你必须使用状态设置函数来修改状态变量以排队重新渲染。 |
你不应该在渲染过程中读取(或写入)current 的值。 |
你可以随时读取state 。但是,每个渲染都有自己的状态快照,不会改变。 |
使用场景
通常来说,当你的组件需要访问 React 之外的内容,如获取外部的APIs(通常是浏览器中不会影响组件变化的 API)时,你将会使用 ref。一些少见的例子:
-
存储 timeout IDs
-
存储和控制 DOM 元素
-
存储计算 JSX 时不需要的其他对象
最佳实践
遵循下面的规则会让你的组件更加具有可预测性:
-
如 “逃生舱” 一般对待 refs 。当你使用外部系统或浏览器API时, refs 是很有用的。如果你的大部分应用程序逻辑和数据流都依赖 refs ,则可能需要重新考虑你的方法。
-
在渲染过程中不要读或写 ref.current 。如果在渲染过程中有一些信息是需要的,请改用 state 。因为 React 不知道
ref.current
会在何时更改 ,甚至在渲染时读取它会使组件的行为难以预测。(唯一的例外是像if (!ref.current) ref.current = new Thing()
这样的代码仅会在第一次渲染时设置它的 ref 值。)
Manipulating the DOM with Refs
使用 ref 最常见的使用场景是获取 DOM 元素。
有时你可能需要访问 React 管理的 DOM 元素,但是,没有内置的方法可以在 React 中做这些事情,因此你需要一个对应于 DOM 节点的 ref ,如 myRef
:
const myRef = useRef(null);
当你将 ref 传递给 JSX 中的 ref 属性时,如 <div ref={myRef} >
,React 会自动地将相应的 DOM 元素放入 MyRef.Current 中。这样就可以从事件处理函数中访问这个 DOM 节点,并使用其上定义的内置浏览器 APIs。
// You can use any browser APIs, for example:
myRef.current.scrollIntoView();
ref callback
如果你想在一个列表渲染中定义多个 ref 来操作列表项,但又不清楚会产生多少个,像下面例子中的方法就不会起作用:
<ul>
{
items.map((item) => {
// Doesn't work!
const ref = useRef(null);
return <li ref={
ref} />;
})}
</ul>
<