当你希望组件"记住"某些信息,但又不想让这些信息 触发新的渲染 时,你可以使用 ref 。
javascript
//通过从 React 导入 useRef Hook 来为你的组件添加一个 ref
import { useRef } from 'react';
export default function Counter() {
//在组件内,调用 useRef Hook 并传入初始值作为唯一参数。
//这里的 ref 指向一个数字,但是,像 state 一样,你可以让它指向任何东西:字符串、对象,甚至是函数。
//与 state 一样,React 会在每次重新渲染之间保留 ref。但是,设置 state 会重新渲染组件,更改 ref 不会!
let ref = useRef(0);
//useRef 返回一个这样的对象:
//{
//current: 0 // 你向 useRef 传入的值
//}
function handleClick() {
ref.current = ref.current + 1;
alert('你点击了 ' + ref.current + ' 次!');
}
return (
<button onClick={handleClick}>
点击我!
</button>
);
}
ref 和 state 的不同之处
ref | state |
---|---|
useRef(initialValue)返回 { current: initialValue } | useState(initialValue) 返回 state 变量的当前值和一个 state 设置函数 ( [value, setValue]) |
更改时不会触发重新渲染 | 更改时触发重新渲染。 |
-- | -- |
可变 ------ 你可以在渲染过程之外修改和更新 current 的值。 | "不可变" ------ 你必须使用 state 设置函数来修改 state 变量,从而排队重新渲染。 |
你不应在渲染期间读取(或写入) current 值。 | 你可以随时读取 state。但是,每次渲染都有自己不变的 state 快照。 |
何时使用 ref
通常,当你的组件需要"跳出" React 并与外部 API 通信时,你会用到 ref ------ 通常是不会影响组件外观的浏览器
API。以下是这些罕见情况中的几个:
- 存储 timeout ID
- 存储和操作 DOM 元素,我们将在 下一页 中介绍
- 存储不需要被用来计算 JSX 的其他对象。
如果你的组件需要存储一些值,但不影响渲染逻辑,请选择 ref。
ref 和 DOM
你可以将 ref 指向任何值。但是,ref 最常见的用法是访问 DOM 元素。列如下面的例子:
javascript
import { useRef } from 'react';
export default function Form() {
//使用 useRef Hook 声明 inputRef
const inputRef = useRef(null);
function handleClick() {
//从 inputRef.current 读取 input DOM 节点并使用 inputRef.current.focus() 调用它的 focus()。
inputRef.current.focus();
}
return (
<>
<input ref={inputRef} /> //这告诉 React 将这个 <input> 的 DOM 节点放inputRef.current。
<button onClick={handleClick}> //用 onClick 将 handleClick 事件处理器传递给 <button>
聚焦输入框
</button>
</>
);
}
ref 的最佳实践
- 当你使用外部系统或浏览器 API 时,ref 很有用。如果你很大一部分应用程序逻辑和数据流都依赖于 ref,你可能需要重新考虑你的方法。
- 不要在渲染过程中读取或写入 ref.current。 如果渲染过程中需要某些信息,请使用 state 代替。由于 React 不知道 ref.current 何时发生变化,即使在渲染时读取它也会使组件的行为难以预测。(唯一的例外是像 if (!ref.current) ref.current = new Thing() 这样的代码,它只在第一次渲染期间设置一次 ref。)
总结
- ref 是一种脱围机制,用于保留不用于渲染的值。 你不会经常需要它们。
- ref 是一个普通的 JavaScript 对象,具有一个名为 current 的属性,你可以对其进行读取或设置。
- 你可以通过调用 useRef Hook 来让 React 给你一个 ref。
- 与 state 一样,ref 允许你在组件的重新渲染之间保留信息。
- 与 state 不同,设置 ref 的 current 值不会触发重新渲染。
- 不要在渲染过程中读取或写入 ref.current。这使你的组件难以预测。