在组件顶层调用 useRef 以声明一个 ref
const ref = useRef(initialValue)
console.log(ref.current)
initialValue:ref 对象的 current 属性的初始值。可以是任意类型的值。这个参数在首次渲染后被忽略。
current 返回一个只有一个属性的对象, 初始值为传递的 initialValue。
可以修改 ref.current 属性。与 state 不同,它是可变的。然而,如果它持有一个用于渲染的对象(例如 state 的一部分),那么就不应该修改这个对象。
改变 ref.current 属性时,React 不会重新渲染组件。
useRef 可以保存 DOM 节点的引用
import { useRef } from 'react';function MyComponent() {const inputRef = useRef(null);// ...return <input ref={inputRef} />;function handleClick() {inputRef.current.focus();}
useRef 也可以保存任何可变的数据,而不用触发组件的重新渲染
// 可以记录定时器id实现防抖
function handleStartClick() {const intervalId = setInterval(() => {// ...}, 1000);intervalRef.current = intervalId;
}
useRef 也可以访问子组件的实例
父组件
import React, { useRef } from 'react';
import ChildComponent from './ChildComponent';
const ParentComponent = () => {const childRef = useRef();const handleClick = () => {childRef.current.focusInput();};return (<div><ChildComponent ref={childRef} /><button onClick={handleClick}>Focus Input</button></div>);
};export default ParentComponent;子组件
import React, { forwardRef, useImperativeHandle, useRef } from 'react';const ChildComponent = forwardRef((props, ref) => {const inputRef = useRef(null);useImperativeHandle(ref, () => ({focusInput() {inputRef.current.focus();}}));return <input ref={inputRef} type="text" />;
});export default ChildComponent;
useRef 也可以useRef 来保存上一次的值,供下次渲染时进行比较或其他操作
不要在渲染期间写入或者读取 ref.current。
function MyComponent() {// ...// 🚩 不要在渲染期间写入 refmyRef.current = 123;// ...// 🚩 不要在渲染期间读取 refreturn <h1>{myOtherRef.current}</h1>;
}可以在 事件处理程序或者 Effect 中读取和写入 ref。
function MyComponent() {// ...useEffect(() => {// ✅ 可以在 Effect 中读取和写入 refmyRef.current = 123;});// ...function handleClick() {// ✅ 可以在事件处理程序中读取和写入 refdoSomething(myOtherRef.current);}// ...
}
如果不得不在渲染期间读取 或者写入,那么应该 使用 state 代替。
避免重复创建 ref 的内容
function Video() {const playerRef = useRef(new VideoPlayer());// ...
虽然 new VideoPlayer() 的结果只会在首次渲染时使用,但是依然在每次渲染时都在调用这个方法。如果是创建昂贵的对象,这可能是一种浪费。为了解决这个问题,你可以像这样初始化 ref:function Video() {const playerRef = useRef(null);if (playerRef.current === null) {playerRef.current = new VideoPlayer();}// ...