Appearance
React Hooks Reference
FreshHooks let you use state and other React features from function components.
State Hooks
useState
Adds a state variable to your component.
jsx
import { useState } from 'react';
function Counter() {
const [count, setCount] = useState(0);
// count: current value
// setCount: updater function
// 0: initial value
}Parameters:
initialState- The value you want the state to be initially. Can be a value or an initializer function.
Returns: [state, setState]
state- The current state valuesetState- The set function to update state and trigger re-render
Caveats:
setStatedoes not changestatein the already-executing code (state is a snapshot)- If the new value is identical to current (by
Object.is), React skips re-rendering - React batches state updates and flushes them together
Updater functions:
jsx
// Replace with value
setCount(5);
// Update based on previous state
setCount(prev => prev + 1);Lazy initialization:
jsx
// Function is called only on first render
const [todos, setTodos] = useState(() => createInitialTodos());useReducer
Manages state with a reducer function.
jsx
import { useReducer } from 'react';
function reducer(state, action) {
switch (action.type) {
case 'increment':
return { count: state.count + 1 };
case 'decrement':
return { count: state.count - 1 };
default:
throw Error('Unknown action: ' + action.type);
}
}
function Counter() {
const [state, dispatch] = useReducer(reducer, { count: 0 });
return (
<>
Count: {state.count}
<button onClick={() => dispatch({ type: 'increment' })}>+</button>
<button onClick={() => dispatch({ type: 'decrement' })}>-</button>
</>
);
}Parameters:
reducer(state, action)- Pure function that takes current state and action, returns next stateinitialArg- Value from which the initial state is calculatedinit?- Optional initializer function. Initial state isinit(initialArg)if provided, elseinitialArg
Context Hooks
useContext
Reads and subscribes to a context.
jsx
import { useContext } from 'react';
import { ThemeContext } from './ThemeContext.js';
function Button() {
const theme = useContext(ThemeContext);
return <button className={theme}>Click me</button>;
}useContext always looks for the closest provider above the component that calls it. It searches upward and does not consider providers in the component from which you're calling useContext.
Ref Hooks
useRef
Declares a ref (a mutable value that doesn't trigger re-renders).
jsx
import { useRef } from 'react';
function Stopwatch() {
const intervalRef = useRef(0); // store a timer ID
const inputRef = useRef(null); // store a DOM node
function handleClick() {
inputRef.current.focus();
}
}Parameters:
initialValue- The value forref.currentinitially
Returns: An object with a single current property, initially set to initialValue
WARNING
Do not read or write ref.current during rendering. Read/write it in event handlers or effects.
useImperativeHandle
Customizes the ref exposed to parent components.
jsx
import { forwardRef, useImperativeHandle, useRef } from 'react';
const MyInput = forwardRef(function MyInput(props, ref) {
const inputRef = useRef(null);
useImperativeHandle(ref, () => ({
focus() {
inputRef.current.focus();
},
scrollIntoView() {
inputRef.current.scrollIntoView();
},
}), []);
return <input {...props} ref={inputRef} />;
});Effect Hooks
useEffect
Connects a component to an external system.
jsx
import { useEffect } from 'react';
function ChatRoom({ roomId }) {
useEffect(() => {
const connection = createConnection(roomId);
connection.connect();
return () => connection.disconnect(); // cleanup
}, [roomId]); // dependency array
}Dependency array behavior:
useEffect(() => {...})- Runs after every renderuseEffect(() => {...}, [])- Runs only on mountuseEffect(() => {...}, [a, b])- Runs on mount and whenaorbchange
useLayoutEffect
Fires before the browser repaints the screen. Use for measuring layout:
jsx
import { useLayoutEffect, useRef, useState } from 'react';
function Tooltip({ children, targetRect }) {
const ref = useRef(null);
const [tooltipHeight, setTooltipHeight] = useState(0);
useLayoutEffect(() => {
const { height } = ref.current.getBoundingClientRect();
setTooltipHeight(height);
}, []);
// Position tooltip based on measured height
}Performance
useLayoutEffect blocks the browser from repainting. Prefer useEffect when possible.
useInsertionEffect
For CSS-in-JS library authors. Fires before any DOM mutations. Don't use in application code.
Performance Hooks
useMemo
Caches the result of a calculation between re-renders.
jsx
import { useMemo } from 'react';
function TodoList({ todos, filter }) {
const visibleTodos = useMemo(
() => filterTodos(todos, filter),
[todos, filter]
);
}Only use useMemo for expensive calculations. Profile first.
useCallback
Caches a function definition between re-renders.
jsx
import { useCallback } from 'react';
function ProductPage({ productId }) {
const handleSubmit = useCallback((orderDetails) => {
post('/product/' + productId + '/buy', { referrer, orderDetails });
}, [productId, referrer]);
return <ShippingForm onSubmit={handleSubmit} />;
}useCallback(fn, deps) is equivalent to useMemo(() => fn, deps).
useTransition
Updates state without blocking the UI.
jsx
import { useState, useTransition } from 'react';
function TabContainer() {
const [isPending, startTransition] = useTransition();
const [tab, setTab] = useState('about');
function selectTab(nextTab) {
startTransition(() => {
setTab(nextTab);
});
}
return (
<>
<TabButton onClick={() => selectTab('about')}>About</TabButton>
<TabButton onClick={() => selectTab('posts')}>Posts</TabButton>
{isPending && <Spinner />}
<TabPanel tab={tab} />
</>
);
}useDeferredValue
Defers updating a part of the UI.
jsx
import { useState, useDeferredValue } from 'react';
function SearchPage() {
const [query, setQuery] = useState('');
const deferredQuery = useDeferredValue(query);
// query updates immediately (for the input)
// deferredQuery updates with a delay (for the results)
}Other Hooks
useId
Generates unique IDs for accessibility attributes.
jsx
import { useId } from 'react';
function PasswordField() {
const passwordHintId = useId();
return (
<>
<input type="password" aria-describedby={passwordHintId} />
<p id={passwordHintId}>Must contain at least 8 characters</p>
</>
);
}DANGER
Don't use useId to generate keys in a list. Keys should come from your data.
use
Reads the value of a resource like a Promise or context.
jsx
import { use } from 'react';
function Comments({ commentsPromise }) {
const comments = use(commentsPromise);
return comments.map(comment => <p key={comment.id}>{comment.text}</p>);
}Unlike other hooks, use can be called inside conditions and loops.
useOptimistic
Shows a different state while an async action is underway.
jsx
import { useOptimistic } from 'react';
function Thread({ messages, sendMessage }) {
const [optimisticMessages, addOptimisticMessage] = useOptimistic(
messages,
(state, newMessage) => [...state, { text: newMessage, sending: true }]
);
async function formAction(formData) {
const message = formData.get('message');
addOptimisticMessage(message);
await sendMessage(message);
}
}useActionState
Manages state for form actions.
jsx
import { useActionState } from 'react';
async function increment(previousState, formData) {
return previousState + 1;
}
function StatefulForm() {
const [state, formAction, isPending] = useActionState(increment, 0);
return (
<form action={formAction}>
{state}
<button disabled={isPending}>Increment</button>
</form>
);
}