React Hooks are functions that let you "hook into" React state and lifecycle features from function components. They were introduced in React 16.8. Below is a list of common React hooks, their explanations, and examples of usage. Additionally, this guide covers how to create custom hooks.
1. useState
The useState
hook lets you add state to function components.
Explanation
useState
returns an array with two elements: the current state value and a function to update it.
Usage
import React, { useState } from 'react';
function Counter() {
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.
useEffect
With Dependencies
-
useEffect
runs after the first render and after every update. You can also specify dependencies to control when the effect runs.
Usage
import React, { useState, useEffect } from 'react';
function Example() {
const [count, setCount] = useState(0);
useEffect(() => {
document.title = `You clicked ${count} times`;
}, [count]);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
useEffect
With an Empty Dependency Array []
- Runs only once after the initial render (similar to componentDidMount).
useEffect(() => {
console.log('This runs only once after the first render');
}, []);
- Use case: Fetching data when the component mounts, setting up event listeners, etc.
useEffect
Without Dependencies
- Runs on every render (initial and subsequent re-renders).
useEffect(() => {
console.log('This runs after every render');
});
- Use case: Running code that doesn’t depend on specific state changes, like logging or animations.
Cleanup Function in useEffect
- If useEffect returns a function, it acts as a cleanup that runs before the next effect or when the component unmounts.
useEffect(() => {
const interval = setInterval(() => {
console.log('Interval running...');
}, 1000);
return () => {
clearInterval(interval); // Cleanup on unmount
};
}, []);
- Use case: Cleaning up event listeners, canceling API calls, clearing intervals, etc.
3. useContext
The useContext
hook lets you access the value of a context.
Explanation
useContext
accepts a context object (the value returned from React.createContext
) and returns the current context value.
Usage
import React, { useContext } from 'react';
const MyContext = React.createContext();
function MyComponent() {
const value = useContext(MyContext);
return <div>{value}</div>;
}
function App() {
return (
<MyContext.Provider value="Hello, World!">
<MyComponent />
</MyContext.Provider>
);
}
4. useReducer
The useReducer
hook is an alternative to useState
for managing complex state logic.
Explanation
useReducer
returns an array with the current state and a dispatch function to trigger state updates.
Usage
import React, { useReducer } from 'react';
const initialState = { count: 0 };
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, initialState);
return (
<div>
<p>Count: {state.count}</p>
<button onClick={() => dispatch({ type: 'increment' })}>
Increment
</button>
<button onClick={() => dispatch({ type: 'decrement' })}>
Decrement
</button>
</div>
);
}
5. useCallback
The useCallback
hook returns a memoized callback.
Explanation
useCallback
returns a memoized version of the callback that only changes if one of the dependencies has changed.
Usage
import React, { useState, useCallback } from 'react';
function Counter() {
const [count, setCount] = useState(0);
const increment = useCallback(() => {
setCount((prevCount) => prevCount + 1);
}, [count]);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={increment}>
Click me
</button>
</div>
);
}
6. useMemo
The useMemo
hook returns a memoized value.
Explanation
useMemo
only recomputes the memoized value when one of the dependencies has changed.
Usage
import React, { useState, useMemo } from 'react';
function ExpensiveCalculationComponent() {
const [count, setCount] = useState(0);
const [value, setValue] = useState('');
const expensiveCalculation = useMemo(() => {
// Assume this is an expensive calculation
return count * 2;
}, [count]);
return (
<div>
<p>Expensive Calculation: {expensiveCalculation}</p>
<button onClick={() => setCount(count + 1)}>Increment</button>
<input value={value} onChange={(e) => setValue(e.target.value)} />
</div>
);
}
7. useRef
The useRef
hook returns a mutable ref object.
Explanation
useRef
is useful for accessing DOM elements or persisting values across renders.
Usage
import React, { useRef } from 'react';
function TextInputWithFocusButton() {
const inputEl = useRef(null);
const onButtonClick = () => {
inputEl.current.focus();
};
return (
<div>
<input ref={inputEl} type="text" />
<button onClick={onButtonClick}>Focus the input</button>
</div>
);
}
8. useImperativeHandle
The useImperativeHandle
hook customizes the instance value that is exposed when using ref
.
Explanation
useImperativeHandle
should be used with React.forwardRef
.
Usage
import React, { useRef, useImperativeHandle, forwardRef } from 'react';
const FancyInput = forwardRef((props, ref) => {
const inputRef = useRef();
useImperativeHandle(ref, () => ({
focus: () => {
inputRef.current.focus();
}
}));
return <input ref={inputRef} />;
});
function Parent() {
const inputRef = useRef();
return (
<div>
<FancyInput ref={inputRef} />
<button onClick={() => inputRef.current.focus()}>Focus Input</button>
</div>
);
}
9. useLayoutEffect
The useLayoutEffect
hook runs after all DOM mutations.
Explanation
useLayoutEffect
is similar to useEffect
, but it fires synchronously after all DOM mutations.
Usage
import React, { useLayoutEffect, useRef } from 'react';
function LayoutEffectComponent() {
const divRef = useRef();
useLayoutEffect(() => {
console.log(divRef.current.getBoundingClientRect());
});
return <div ref={divRef}>Hello, world!</div>;
}
10. useDebugValue
The useDebugValue
hook is used to display a label for custom hooks in React DevTools.
Explanation
useDebugValue
can be helpful for debugging custom hooks.
Usage
import React, { useState, useDebugValue } from 'react';
function useFriendStatus(friendID) {
const [isOnline, setIsOnline] = useState(null);
useDebugValue(isOnline ? 'Online' : 'Offline');
// Imagine this is an actual implementation
return isOnline;
}
11. Custom Hooks
Custom hooks let you extract component logic into reusable functions.
Explanation
Custom hooks are normal JavaScript functions that can call other hooks.
Example: useFetch
import { useState, useEffect } from 'react';
function useFetch(url) {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
fetch(url)
.then((response) => response.json())
.then((data) => {
setData(data);
setLoading(false);
});
}, [url]);
return { data, loading };
}
export default useFetch;
Usage of Custom Hook
import React from 'react';
import useFetch from './useFetch';
function App() {
const { data, loading } = useFetch('https://api.example.com/data');
if (loading) {
return <div>Loading...</div>;
}
return (
<div>
<pre>{JSON.stringify(data, null, 2)}</pre>
</div>
);
}
export default App;
This guide provides a comprehensive overview of React hooks, their usage, and how to create custom hooks.