React Hooks, introduced in React 16.8, allow you to use state and other React features without writing a class. Hooks provide a more direct API to React concepts you already know: props, state, context, refs, and lifecycle. Here’s a guide to understanding all the built-in hooks in React.
1. useState
The useState
hook allows you to add state to your functional components.
import { useState } from 'react';
function Example() {
const [count, setCount] = useState(0);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>Click me</button>
</div>
);
}
2. useEffect
The useEffect
hook lets you perform side effects in function components, such as data fetching, subscriptions, or manually changing the DOM.
import { useState, useEffect } from 'react';
function Example() {
const [count, setCount] = useState(0);
useEffect(() => {
document.title = `You clicked ${count} times`;
});
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>Click me</button>
</div>
);
}
3. useContext
The useContext
hook lets you subscribe to React context without introducing nesting.
import { useContext } from 'react';
import { ThemeContext } from './ThemeContext';
function ThemedButton() {
const theme = useContext(ThemeContext);
return <button style={{ background: theme.background, color: theme.foreground }}>I'm styled by theme context!</button>;
}
4. useReducer
The useReducer
hook is an alternative to useState
that’s preferable for complex state logic that involves multiple sub-values or when the next state depends on the previous one.
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 new Error();
}
}
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>
</>
);
}
5. useCallback
The useCallback
hook returns a memoized version of the callback that only changes if one of the dependencies has changed. This is useful when passing callbacks to optimized child components that rely on reference equality to prevent unnecessary renders.
import { useCallback } from 'react';
function Example({ someProp }) {
const memoizedCallback = useCallback(() => {
doSomething(someProp);
}, [someProp]); // Only recreates the callback if `someProp` changes
}
6. useMemo
The useMemo
hook returns a memoized value, only re-computing the memoized value when one of the dependencies has changed.
import { useMemo } from 'react';
function Example({ a, b }) {
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]); // Only re-runs the
expensive function if `a` or `b` changes
}
7. useRef
The useRef
hook is useful for accessing DOM nodes or keeping any mutable value around, similar to how you’d use instance fields in classes.
import { useRef } from 'react';
function TextInputWithFocusButton() {
const inputEl = useRef(null);
const onButtonClick = () => {
// `current` points to the mounted text input element
inputEl.current.focus();
};
return (
<>
<input ref={inputEl} type="text" />
<button onClick={onButtonClick}>Focus the input</button>
</>
);
}
8. useImperativeHandle
The useImperativeHandle
hook customizes the instance value that is exposed to parent components when using ref.
import { useImperativeHandle, useRef, forwardRef } from 'react';
function FancyInput(props, ref) {
const inputRef = useRef();
useImperativeHandle(ref, () => ({
focus: () => {
inputRef.current.focus();
}
}));
return <input ref={inputRef} ... />;
}
FancyInput = forwardRef(FancyInput);
9. useLayoutEffect
The useLayoutEffect
hook 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.
import { useLayoutEffect } from 'react';
useLayoutEffect(() => {
// Your code here. Similar to componentDidMount and componentDidUpdate.
});
10. useDebugValue
The useDebugValue
hook can be used to display a label for custom hooks in React DevTools.
import { useDebugValue } from 'react';
function useFriendStatus(friendID) {
const isOnline = // Some logic...
useDebugValue(isOnline ? 'Online' : 'Offline');
return isOnline;
}
React Hooks are a powerful addition to React, giving you the tools to write your components in a simpler and more intuitive way, without sacrificing any of the power or flexibility of React. Remember, Hooks are completely opt-in and 100% backwards-compatible. You can use Hooks in all your new components, while keeping your old class-based components as they are.