Skip to main content

钩子语法

Hook 语法是对 React 钩子的一流语法和类型检查支持,将钩子作为其自己的实体引入到 React 语言中,这些实体在语法和语义上与常规函数不同,并使用 Flow 强制不违反 反应规则

¥Hook Syntax is first-class syntax and typechecking support for React hooks, bringing hooks into the React language as their own entities that are syntactically and semantically distinct from regular functions, and using Flow to enforce that the Rules of React aren’t violated.

基本用法

¥Basic Usage

编写函数和钩子之间的主要区别是 hook 关键字:

¥The primary difference between writing a function and a hook is the hook keyword:

1import {useState, useEffect} from 'react';2
3hook useOnlineStatus(initial: boolean): boolean {4  const [isOnline, setIsOnline] = useState(initial);5  useEffect(() => {6    // ...7  }, []);8  return isOnline;9}

钩子可以像常规函数一样被调用:

¥Hooks can be called just like regular functions:

1import * as React from 'react';2
3hook useOnlineStatus(): boolean {4    return true;5}6
7component StatusBar() {8  const isOnline = useOnlineStatus();9  return <h1>{isOnline ? '✅ Online' : '❌ Disconnected'}</h1>;10}

钩子可以像普通函数一样导出:

¥Hooks can be exported just like normal functions:

1export hook useNamedExportedHook(): boolean {2    return true;3}4
5export default hook useDefaultExportedHook(): boolean {6    return true;7}

钩子类型注释

¥Hook Type Annotations

在某些情况下,你可能希望将值定义为具有钩子类型。由于函数类型和钩子类型不兼容(更多内容见下文!),我们还引入了钩子类型注释的新语法,它只是现有的函数类型注释,但前面有钩子。

¥There are a few cases where you might wish to define a value as having the type of a hook. Because function types and hook types aren’t compatible (more on this below!), we also introduce a new syntax for hook type annotations, which is simply the existing function type annotation but preceded by hook.

export const useGKOnlineStatus: hook (boolean) => boolean = 
experiment('show_online_status')
? useOnlineStatus
: useAlwaysOnlineStatus

使用 Hook 语法强制执行 React 规则

¥Enforcing the Rules of React with Hook Syntax

通过钩子语法,我们现在可以在语法上明确地区分钩子和非钩子。Flow 将使用此信息来强制执行一些钩子和 反应规则 的规则。

¥With hook syntax, we can now unambiguously distinguish syntactically between hooks and non-hooks. Flow will use this information to enforce a number of the rules of hooks and Rules of React generally.

防止不安全突变

¥Preventing Unsafe Mutation

根据 反应规则,在组件渲染时不允许读取或写入 ref,并且其他钩子(尤其是 useState)的返回值根本不能安全地直接改变。通过让 Flow 将钩子视为一流概念,我们现在可以在许多情况下检测到这些问题并尽早提出错误,而不是依靠测试来发现它们。

¥According to the Rules of React, refs aren’t allowed to be read from or written to while a component is rendering, and the return value of other hooks (especially `useState``) cannot be safely mutated directly at all. By making Flow aware of hooks as a first-class concept, we can now detect these issues in many cases and raise errors early, rather than depending on testing to uncover them.

1import {useState, useEffect, useRef} from 'react';2import * as React from 'react';3
4component MyComponent() { 5  const ref = useRef<?number>(null);6  const [state, setState] = useState<{ val: number }>({val: 0});7
8  state.val = 42; // Flow error: cannot mutate return value of hook9
10  return (11    <div>12      {ref.current /* Flow error: cannot read ref during rendering */}13    </div>14  );15}

Flow 目前阻止组件内的组件 props 被修改。钩子语法允许我们将这种检查扩展到钩子,并且可以让我们在钩子声明中发生非法突变时检测并引发错误。

¥Flow currently prevents component props from being modified within the component. Hook syntax allows us to extend this checking to hooks, and will let us detect and raise errors when illegal mutations occur within hook declarations.

1hook useIllegalMutation(values: Array<number>) {2  values[0] = 42; // Flow error: mutating argument to hook3  // ...4}

防止条件钩子调用

¥Preventing Conditional Hook Calls

Hook 的规则 禁止有条件地调用钩子。React 的 ESLint 插件 涵盖了这一点,但现在 Flow 也会检查这些违规行为。

¥The Rules of Hooks prohibit hooks from being called conditionally. This is covered by React's ESLint plugin, but now Flow will check for these violations too.

1hook useOnlineStatus(): boolean {2    return true;3}4
5component StatusBar(shouldShowOnlineStatus: boolean) {6  if (shouldShowOnlineStatus) {7    const onlineStatus = useOnlineStatus();8  }9
10  return null;11}

防止钩子和函数的合并

¥Preventing Conflation of Hooks and Functions

钩子和常规函数之间的区别体现在 Flow 类型系统中。由于钩子和函数必须遵守不同的属性,因此将定义为钩子的值传递到需要函数类型的位置是流错误,而将常规 JavaScript 函数传递到需要钩子的位置是错误。

¥The distinction between hooks and regular functions is reflected in the Flow type system. Because of the different properties that hooks and functions must obey, it’s Flow error to pass a value defined as a hook into a position that expects a function type, and an error to pass a regular JavaScript function into a position that expects a hook.

1import {useState, useEffect} from 'react';2
3hook useMultiplier(x: number): number {4  const [y, setY] = useState(1);5  useEffect(() => { setY(0) })6  return x * y;7}8
9component Mapper(args: Array<number>) {10  const multArgs = args.map(useMultiplier);11  12  return multArgs;13}

此外,Flow 强制要求钩子和组件内具有类似钩子名称的被调用者确实是钩子。我们还确保常规函数定义内的被调用者永远不会是钩子。

¥In addition, Flow enforces that callees with hook-like names inside hooks and components are indeed hooks. We also ensure that callees inside of regular function definitions are never hooks.

1hook useHook() { return null }2
3function regularJavascript() {4  const x = useHook(); // Flow error: cannot call a hook outside of a component or hook5}6
7component Component() { 8  const renamedHook = useHook;9  renamedHook(); // Flow error: cannot call a hook whose name does not begin with `use`10
11  return null;12}