type
status
date
slug
summary
tags
category
icon
password
Hook
Hook概述
Hook可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性。
- 基础 Hook(opens new window)
- useState (opens new window)定义和修改渲染依赖的数据。
- useEffect (opens new window)生命周期回调。
- useContext (opens new window)可创建跨组件数据依赖。
- 额外的 Hook(opens new window)
- useReducer (opens new window)另一种 useState ,使用 dispatch 的方式更新数据。
- useCallback (opens new window)返回一个 memoized (opens new window)回调函数,该回调函数仅在某个依赖项改变时才会更新。
- useMemo (opens new window)返回一个 memoized (opens new window)值,它仅会在某个依赖项改变时才重新计算。
- useRef (opens new window)返回一个可变的 ref 对象,能够很方便地保存任何可变值 (opens new window),可绑定在组件或元素上以实现对其的引用。
- useImperativeHandle (opens new window)可以让你在使用
ref
时自定义暴露给父组件的实例值。 - useLayoutEffect (opens new window)用法与 useEffect 相同,但是会在所有的 DOM 变更之后同步调用 effect。
- useDebugValue (opens new window)用于在 React 开发者工具中显示自定义 hook 的标签。
- useDeferredValue (opens new window)延迟你传递给它的值。与使用防抖和节流去延迟更新的用户空间 hooks 类似。
- useTransition (opens new window)启动一个过渡任务,可以让更紧急地更新先进行。
- useId (opens new window)生成一个唯一标识符。
- Library Hooks(opens new window)
什么是 Hook?
Hook 是一个特殊的函数,可以让你在函数组件里“钩入” React state 及 生命周期 等特性的函数。
Hook 不能在 class 组件中使用 —— 这使得你不使用 class 也能使用 React。React 内置了一些像 useState 这样的 Hook。你也可以创建你自己的 Hook 来复用不同组件之间的状态逻辑。我们会先介绍这些内置的 Hook。
useState(状态钩子)
模式:
上面的三个值均可自定义名称,分别是:
- state取值变量名
- state设值方法名
- 初始值
- 初始值可以是数字、字符串、对象、数组等
例子:
声明多个 state 变量
Effect Hook (副作用钩子)
你之前可能已经在 React 组件中执行过数据获取、订阅 或者手动修改 DOM。我们统一把这些操作称为“副作用”,或者简称为“作用”。
useEffect(生命周期钩子)
useEffect
就是一个 Effect Hook,给函数组件增加了操作副作用的能力。它跟 class 组件中的 componentDidMount
、componentDidUpdate
和 componentWillUnmount
具有相同的用途,只不过被合并成了一个 API。(我们会在使用 Effect Hook (opens new window)里展示对比 useEffect
和这些方法的例子。)例如,下面这个组件在 React 更新 DOM 后会设置一个页面标题:
当你调用
useEffect
时,就是在告诉 React 在完成对 DOM 的更改后运行你的“副作用”函数。由于副作用函数是在组件内声明的,所以它们可以访问到组件的 props 和 state。默认情况下,React 会在每次渲染后调用副作用函数 —— 包括第一次渲染的时候。“清除”副作用
副作用函数还可以通过返回一个函数来指定如何“清除”副作用。例如,在下面的组件中使用副作用函数来订阅好友的在线状态,并通过取消订阅来进行清除操作:
在这个示例中,React 会在组件销毁时取消对
ChatAPI
的订阅,然后在后续渲染时重新执行副作用函数。(如果传给 ChatAPI
的 props.friend.id
没有变化,你也可以告诉 React 跳过重新订阅 (opens new window)。)跟
useState
一样,你可以在组件中多次使用 useEffect
:通过使用 Hook,你可以把组件内相关的副作用组织在一起(例如创建订阅及取消订阅),而不要把它们拆分到不同的生命周期函数里。
详细说明你可以在这一章节了解更多关于useEffect
的内容:使用 Effect Hook(opens new window)
Hook 使用规则
Hook 就是 JavaScript 函数,但是使用它们会有两个额外的规则:
- 只能在函数最外层调用 Hook。不要在循环、条件判断或者子函数中调用。
- 只能在 React 的函数组件中调用 Hook。不要在其他 JavaScript 函数中调用。(还有一个地方可以调用 Hook —— 就是自定义的 Hook 中,我们稍后会学习到。)
同时,我们提供了 linter 插件 (opens new window)来自动执行这些规则。这些规则乍看起来会有一些限制和令人困惑,但是要让 Hook 正常工作,它们至关重要。
详细说明你可以在这章节了解更多关于这些规则的内容:Hook 使用规则 (opens new window)。
自定义 Hook (Hook的使用逻辑封装)
有时候我们会想要在组件之间重用一些状态逻辑。目前为止,有两种主流方案来解决这个问题:高阶组件 (opens new window)和 render props (opens new window)。自定义 Hook 可以让你在不增加组件的情况下达到同样的目的。
前面,我们介绍了一个叫
FriendStatus
的组件,它通过调用 useState
和 useEffect
的 Hook 来订阅一个好友的在线状态。假设我们想在另一个组件里重用这个订阅逻辑。首先,我们把这个逻辑抽取到一个叫做
useFriendStatus
的自定义 Hook 里:它将
friendID
作为参数,并返回该好友是否在线:现在我们可以在两个组件中使用它:
每个组件间的 state 是完全独立的。Hook 是一种复用*状态逻辑*的方式,它不复用 state 本身。事实上 Hook 的每次调用都有一个完全独立的 state —— 因此你可以在单个组件中多次调用同一个自定义 Hook。
自定义 Hook 更像是一种约定而不是功能。如果函数的名字以 “
use
” 开头并调用其他 Hook,我们就说这是一个自定义 Hook。 useSomething
的命名约定可以让我们的 linter 插件在使用 Hook 的代码中找到 bug。你可以创建涵盖各种场景的自定义 Hook,如表单处理、动画、订阅声明、计时器,甚至可能还有更多我们没想到的场景。我们很期待看到 React 社区会出现什么样的自定义 Hook。
详细说明我们会在这一章节介绍更多关于自定义 Hook 的内容: 创建你自己的 Hook (opens new window)。
其他 Hook
除此之外,还有一些使用频率较低的但是很有用的 Hook。比如,
useContext
(opens new window)让你不使用组件嵌套就可以订阅 React 的 Context。另外
useReducer
(opens new window)可以让你通过 reducer 来管理组件本地的复杂 state。详细说明你可以在这一章节了解更多关于所有内置 Hook 的内容:Hook API 索引 (opens new window)。
- 作者:慕雨
- 链接:https://www.axin.work/article/f692fa13-e248-4624-8645-c94c10766b05
- 声明:本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。