Skip to main content

Hook Syntax

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

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}
Try

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}
Try

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}
Try

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.

1declare function experiment(name: string): boolean;2declare hook useOnlineStatus(x: boolean): boolean;3declare hook useAlwaysOnlineStatus(x: boolean): boolean;4
5export const useGKOnlineStatus: hook (boolean) => boolean =6  experiment('show_online_status')7  ? useOnlineStatus8  : useAlwaysOnlineStatus
Try

Enforcing the Rules of React with Hook Syntax

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

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; // Error: cannot mutate return value of hookreact-rule-hook-mutationCannot assign 42 to state.val because property val is not writable.9
10  return (11    <div>12      {ref.current /* Error: cannot read ref during rendering */}react-rule-unsafe-refCannot read current from ref [1] because ref values may not be read during render. ().13    </div>14  );15}
Try

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; // Error: mutating argument to hookreact-rule-unsafe-mutationCannot assign 42 to values[0] because read-only arrays cannot be written to.