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}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.
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 : useAlwaysOnlineStatusEnforcing 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}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.