Basic Hooks

useState

1
const [state, setState] = useState(initialState)

Returns a stateful value and a function to update it.

During subsequent re-renders, the first value returned by useState will always be the most recent state after applying updates.

Functional updates

If the new state is computed using the previous state, you can pass a function to setState. The function will receive the previous value and return an updated value.

Note: Unlike the setState method found in class component, useState does not automatically merge upate objects.

useReducer is more suited for managing state objects that contains multiple sub-values.

Lazy initialization

The initialState argument is the state used during the initial render. In subsequent renders, it is disregarded. If the initial state is the result of an expensive computation, you may provide a function instead, which will be executed only on the initial render.

useEffect

1
useEffect(didUpdate)

Accept a function that contains imperative, possibly effectful code.

Mutations, subscriptions, timers, logging and other side effects are not allowed inside the main body of a function component. Instead, use useEffect. The functino passed to useEffect will run after the render is committed to the screen.

By default, effects run after every completed render, but you can choose to fire it only when certain values have changed.

Cleaning up an effect

1
2
3
4
5
6
7
useEffect(() => {
const subscription = props.source.subscribe()
return () => {
// Clean up the subscription
subscription.unsubscribe()
}
})

Timing of effects

Unlike componentDidMount and componentDidUpdate, the function passed to useEffect fires after layout and paint, during a deferred event. This makes it suitable for the many common side effects, like setting up subscriptions and event handlers, because most types fo work shouldn’t block the browser from updating the screen.

useMutationEffect and useLayoutEffect have the same signature as useEffect and only differ in when they are fired.

Although useEffect is deferred until after the browser has painted, it’s guaranteed to fire before any new renders.

Conditionally firing an effect

1
2
3
4
5
6
7
useEffect(
() => {
const subscription = props.source.subscribe()
return () => subscription.unsubscribe()
},
[props.source],
)

useContext

1
const context = useContext(Context)

Accepts a context object(the value returned from React.createContext) and returns the current context value, as given by the nearest context provider for the given context.

When the provider updates, this hook will trigger a rerender with the latest context value.

Additional Hooks

useReducer

1
const [state, dispatch] = useReducer(reducer, initialState)

An alternative to useState. Accepts a reducer of type (state, action) => newState, and returns the current state paired with a dispatch method.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
const initialState = { count: 0 }

function reducer(state, action) {
switch (action.type) {
case 'reset': {
return initialState
}
case 'increment': {
return { count: state.count + 1 }
}
case 'decrement': {
return { count: state.count - 1 }
}
default:
return state
}
}

function Counter({ initialCount }) {
const [state, dispatch] = useReducer(reducer, { count: initialCount })
return (
<>
Count: {state.count}
<button onClick={() => dispatch({ type: 'reset' })}>Reset</button>
</>
)
}

Lazy initialization

useReducer accepts an optional third argument, initialAction. If provided, the initial action is applied during the initial render. This is useful for computing an initial state that includes values passed via props.

useCallback

1
2
3
4
5
6
const memoizedCallback = useCallback(
() => {
doSomething(a, b)
},
[a, b],
)

Returns memoized callback.

Pass an inline callback and an array of inputs, useCallback will return a memoized version of the callback that only changes if one of the inputs has changed. This is useful when passing callbacks to optimized child components that rely on reference equality to prevent unnecessary render.

Note: The array of inputs is not passed as arguments to the callback. Conceptually, though, that’s what represent: every value referenced inside the callback should also appear in the inputs array.

useMemo

1
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b])

Returns a memoized value.

Pass a “create” function and an array of inputs, useMemo will only recompute the memoized value when one of the inputs has changed. This optimization helps to avoid expensive calculations on every render.

If no array is provided, a new value will be computed whenever a new function instance is passed as the first argument.(With an inline function, on every render)

useRef

1
const refContainer = useRef(initialValue)

useRef returns a mutable ref object whose .current property is initialized to the passed argument(initialValue). The returned object will persist for the full lifetime of the component.

A common use case is to access a child imperatively:

1
2
3
4
5
6
7
8
9
10
11
12
function TextInputFocusButton() {
const inputEl = useRef(null)
const onButtonClick = () => {
inputEl.current.focus()
}
return (
<>
<input ref={inputEl} type="text" />
<button onClick={onButtonClick}>Focus the input</button>
</>
)
}

useImperativeMethods

1
useImperativeMethods(ref, createInstance, [inputs])

useImperativeMethods customizes the instance value that is exposed to parent component when use ref. As always, imperative code using refs should be avoided in most cases. useImperativeMethods should be used with forwardRef

1
2
3
4
5
6
7
8
9
10
function FancyInput(props, ref) {
const inputRef = useRef()
useImperativeMethods(ref, () => ({
focus: () => {
inputRef.current.focus()
},
}))
return <input ref={inputRef} />
}
FancyInput = forwardRef(FancyInput)

In this example, a parent component that renders <FancyInput ref={fancyInputRef} /> would be able to call fancyInputRef.current.focus().

useMutationEffect

The signature is identical to useEffect, but it fires synchronously during the same phase that React performs its DOM mutations, before sibling components has been updated.

Prefer the standard useEffect when possible to avoid blocking visual updates.

Note: Avoid reading from the DOM in useMutationEffect. If you do, you can cause performance problems by introducing layout trash.

useLayoutEffect

The signature is identical to useEffect but it fires synchronously after all DOM mutations.

Use this to read layout from the DOM and synchronously re-render. Updates scheduled inside useLayoutEffect will be flushed synchronously, before the browser has a chance to paint.

Fires in the same phase as componentDidMount and componentDidUpdate