用途

1. 声明变量

希望组件“记住”某些信息,但又不想让这些信息 触发新的渲染 时 (能够跨渲染周期保存值)

import { useRef } from 'react';
 
const ref = useRef(0);
// useRef 返回一个这样的对象:
// {
//   current: 0 // 你向 useRef 传入的值
// }
 
// 使用:
ref.current = 1

2.操作 DOM

import { useRef } from 'react';
 
const myRef = useRef(null);
 
return (
  <div ref={myRef}></div>
)
 
// 使用:
myRef.current.focus()

Warning

不能在渲染期间直接使用 ref 进行操作(即不能直接写在组件内最外层中的逻辑代码中,一般写在事件或函数中),因为此时 DOM 节点尚未创建

如下面的写法是错误的:

function VideoPlayer({ src, isPlaying }) {
  const ref = useRef(null);
 
  if (isPlaying) {
    ref.current.play();  // 渲染期间不能调用 `play()`。 
  } else {
    ref.current.pause(); // 同样,调用 `pause()` 也不行。
  }
 
  return <video ref={ref} src={src} loop playsInline />;
}

动态 ref

因为 Hook 只能在组件的顶层被调用,所以 ref 的数量需要是预先确定的。但有时候,可能需要为列表中的每一项都绑定 ref ,而又不知道会有多少项

解决方法:

将函数传递给 ref 属性

<div ref={(node) => {
  console.log('Attached', node);
 
  return () => {
    console.log('Clean up', node)
  }
}}>
  • <div> DOM 节点被添加到屏幕上时,React 将使用该节点作为参数调用 ref 回调函数。
  • 当这个 <div> DOM 节点被移除的时候, React 将调用回调返回的清理函数。

在上面的示例中,(node) => { ... } 在每次渲染时都是一个不同的新函数。当组件重新渲染时,先前的函数将被调用并传递 null 作为参数,并且下一个新函数将被调用并传递对应 DOM 节点作为参数。