Hooks 概览

Hooks 是在 React 组件中引入和管理状态和副作用的基本机制。

什么是 Hook ?

在前面的章节中,我们学到了 React 组件是基于特定 props 值的简单函数,用于表示 UI。为了使应用更可用,我们需要一种通过用户输入或向服务器发送请求来加载数据,从而交互式地操作 props 的方法。

这就是 Hook 的用武之地。Hook 是一种函数,它让我们可以为组件引入状态,并为不同的任务触发副作用,例如 HTTP 请求、直接访问 HTML DOM、获取窗口大小等等。

换句话说:Hook 可以让我们“钩入” React 特性。

示例: useState Hook

让我们看一个例子,下面是一个 Counter 组件,它允许用户通过点击按钮来增加 count 值,并且新的 count 值会在按钮点击时被渲染:

ReScriptJS Output
// Counter.res
@react.component
let make = () => {
  let (count, setCount) = React.useState(_ => 0);

  let onClick = (_evt) => {
    setCount(prev => prev + 1)
  };

  let msg = "You clicked" ++ Belt.Int.toString(count) ++  "times"

  <div>
    <p>{React.string(msg)}</p>
    <button onClick> {React.string("Click me")} </button>
  </div>
}

我们使用了 React.useState Hook。我们在组件函数中调用它来为组件添加局部状态。React 会在重渲染之间保持这些状态。React.useState 返回一个元组,包括当前状态值(count) 和一个更新状态值的函数(setCount)。你能在处理事件时调用更新函数,或将更新函数传递给其他组件。

React.useState 的唯一参数是一个返回初始状态的函数(_ => 0)。在上面的例子中,它是 0 ,因为我们的计数器从零开始。请注意,状态可以是任何类型,Rescript 会为你进行类型推断(只需要确保你的初始状态和你的类型匹配)。初始状态参数只会在首次渲染时使用。

这只是 Hook 的一个小例子。我们会在独立的 useState 章节中介绍更多细节。

可用的 Hooks

注意: 所有 Hooks 都在 React 模块下(例如 React.useState)。

基础 Hooks:

  • useState: 为组件添加局部状态

  • useEffect: 在组件内运行有副作用的代码

  • useContext: 让你的组件能访问 React Context

额外 Hooks:

  • useReducer: useState 的替代方案,使用state / action / reduce 模式

  • useRef: 返回一个可变的 React Ref 值

Hooks 规则

Hooks 本质上是些简单函数,但是你需要在使用时遵循 两条规则。ReScript 不会在编译器中强制执行这些规则,如果你想要强制执行正确的 Hooks 约定,可以使用 eslint-plugin 来检查编译的 JS 输出。

1. 只在最顶层调用 Hook

不要在循环,条件或嵌套函数中调用 Hooks,确保总是在你的 React 函数的最顶层调用它们。遵守这条规则,你就能确保 Hook 在每一次渲染中都按照同样的顺序被调用。这让 React 能够在多次的 useStateuseEffect 调用之间正确保持 Hooks 状态。(如果你对此感到好奇,ReactJS Hooks 文档 有更深入的解释。)

2. 只在 React 函数中调用 Hook

不要在普通的 JavaScript 函数中调用 Hook。 你可以:

  • ✅ 在 React 的函数组件中调用 Hook

  • ✅ 在自定义 Hook 中调用其他 Hook (我们将会在 自定义 hooks 章节中学习。)

遵循这些规则,确保组件的状态逻辑在代码中清晰可见。