内置 React Hook

Hook 让你可以在组件中使用不同的 React 功能。你可以使用内置的 Hook 或者把它们组合起来建立你自己的。本页列出了 React 中所有的内置 Hook。


状态 Hook

State 让一个组件 “记住” 像用户输入的信息,比如,要给一个组件添加状态,使用这些 Hook 中的一个:

function ImageGallery() {
const [index, setIndex] = useState(0);
// ...

Context Hook

Context 让一个组件从远处的父组件接收信息,而不需要将其作为 props 传递。 比如,app 的顶层组件可以将当前的 UI 主题传递给下面的所有组件,无论它们层级多深。

function Button() {
const theme = useContext(ThemeContext);
// ...

Ref Hook

Ref 让一个组件持有一些不用于渲染的信息,如 DOM 节点或一个 timeout ID。与 state 不同的是,更新 Ref 并不会重新渲染你的组件。Ref 是 React 范式的一个 “逃生舱门”。当你需要与非 React 系统一起工作时,它们很有用,比如内置的浏览器 API。

  • useRef 声明了一个 Ref。你可以在其中保存任何值,但最常见的是它用来保存一个 DOM 节点。
  • useImperativeHandle 可以让你自定义你的组件所暴露的 Ref。这一点很少使用。
function Form() {
const inputRef = useRef(null);
// ...

Effect Hook

Effect 让一个组件连接到外部系统并与之同步。这包括处理网络、浏览器、DOM、动画、使用不同 UI 库编写的 widgets 以及其他非 React 代码。

  • useEffect 将一个组件连接到外部系统。
function ChatRoom({ roomId }) {
useEffect(() => {
const connection = createConnection(roomId);
connection.connect();
return () => connection.disconnect();
}, [roomId]);
// ...

Effect 是 React 范式的 “逃生舱门”。不要用 Effect 来协调你的应用程序的数据流。如果你不与外部系统交互,你可能不需要 Effect。

useEffect 有两个很少使用的变体,它们在时间上有差异:

  • useLayoutEffect 在浏览器重绘屏幕前启动。你可以在这里测量布局。
  • useInsertionEffect 在 React 对 DOM 进行修改之前触发。Libraries 可以在这里插入动态 CSS。

性能 Hook

优化重新渲染性能的一个常见方法就是跳过不必要的工作。比如,你可以告诉 React 重用一个缓存的计算,或者如果数据在上一次渲染后没有变化,就跳过一次重新渲染。

要跳过计算和不必要的重新渲染,请使用这些 Hook 的一个:

  • useMemo 让你缓存一个高昂的计算结果。
  • useCallback 让你在将一个函数定义传递给一个优化的组件之前缓存它。
function TodoList({ todos, tab, theme }) {
const visibleTodos = useMemo(() => filterTodos(todos, tab), [todos, tab]);
// ...
}

有时,你不能跳过重新渲染,因为屏幕确实需要更新。在这种情况下,你可以通过将必须同步的阻塞更新(比如向输入法输入)与不需要阻塞用户界面的非阻塞更新(比如更新图表)分开以提高性能。

要确定渲染的优先级,可以使用这些 Hook 的一个:

  • useTransition 让你把一个状态转换标记为非阻塞,并允许其他更新中断它。
  • useDeferredValue 让你推迟更新用户界面的一个非关键部分,让其他部分更新。

其他 Hook

这些 Hook 主要对 library 的作者有用,在应用代码中并不常用。

  • useDebugValue 让你在 React DevTools 中为自定义 Hook 添加一个 label。
  • useId 让组件将一个独特的 ID 与自己联系起来。通常与可访问性 API 一起使用。
  • useSyncExternalStore 让一个组件订阅一个外部 store。

自己的 Hook

你也可以在 JavaScript 函数中定义你自己的 Hook。