Mastering React Hooks: A Comprehensive Guide with Examples
Gurdeep Jain
Posted on May 11, 2024
Introduction:
React Hooks have revolutionized how developers write React components by allowing them to use state and other React features without writing a class. With the introduction of Hooks in React 16.8, developers gained a powerful toolset to manage stateful logic and side effects in functional components. In this blog post, we'll delve into the all-important React Hooks, explaining each in detail with practical examples.
useState():
useState()
is the most fundamental Hook in React. It allows functional components to manage the state within themselves. Here's a basic example:
import React, { useState } from 'react';
function Counter() {
const [count, setCount] = useState(0);
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);
}
useEffect():
useEffect()
enables developers to perform side effects in functional components. It replaces componentDidMount, componentDidUpdate, componentWillUnmount lifecycle method. Here's the basic structure of useEffect:
useEffect(() => {
// Side effect code
// This code will run after every render
return () => {
// Cleanup code (optional)
// This code will run before the component unmounts
};
}, [/* dependencies */]);
useEffect contains two arguments first
is a function, in This function is the side effect you want to perform. It will run after every render by default. You can return a cleanup function from this function (optional) to perform cleanup before the component unmounts and the second
is an array of dependencies. It's an optional array that contains values (usually props or state) that the effect depends on. If any of the dependencies change between renders, the effect will be re-run. If you omit this array, the effect runs after every render. If you provide an empty array, the effect only runs once.
Here's an example to illustrate useEffect:
import React, { useState, useEffect } from 'react';
function Timer() {
const [seconds, setSeconds] = useState(0);
useEffect(() => {
const interval = setInterval(() => {
setSeconds(prevSeconds => prevSeconds + 1);
}, 1000);
return () => {
clearInterval(interval);
};
}, []); // Empty dependencies array means the effect runs only once
return (
<div>
Seconds: {seconds}
</div>
);
}
export default Timer;
useRef():
useRef
is a hook in React that provides a way to create mutable references that persist across renders without causing the component to re-render when the reference changes. It's commonly used to access DOM elements or to persist values between renders without triggering a re-render.
import React, { useRef, useEffect } from 'react';
function InputWithFocusButton() {
const inputRef = useRef(null);
useEffect(() => {
inputRef.current.focus();
}, []);
return (
<div>
<input ref={inputRef} type="text" />
<button onClick={() => inputRef.current.focus()}>Focus the input</button>
</div>
);
}
export default InputWithFocusButton;
In this example:
We have InputWithFocusButton component that contains an input element and a button. We use useRef
to create a reference to the input element(inputRef). We use useEffect with an empty dependency array to focus the input element when the component is mounted. We set the ref
attribute of the input element to inputRef
, allowing us to access the input element using inputRef.current. We use inputRef.current.focus()
to focus the input element both in the useEffect and when the button is clicked.
UseMemo()
useMemo
is a hook that is used for memorization in React. Memoization is a technique to optimize performance by caching the result of expensive function calls and returning that cached result when the same inputs occur again.
In useMemo()
we pass a function as the first
argument. This function is an expensive computation you want to memorise. The second
argument is an array of dependencies. The memoized value will only be recalculated if one of these dependencies changes.
Example:
import React, { useMemo, useState } from 'react';
function Fibonacci({ n }) {
const calculateFibonacci = (n) => {
if (n <= 1) return n;
return calculateFibonacci(n - 1) + calculateFibonacci(n - 2);
};
const result = useMemo(() => calculateFibonacci(n), [n]);
return <div>The {n}th Fibonacci number is {result}</div>;
}
In this example, calculateFibonacci is an expensive function to calculate Fibonacci numbers. We use useMemo
to memoize the result of calculateFibonacci(n)
based on the n prop. This ensures that the Fibonacci calculation is only performed when the n prop changes.
useCallback()
useCallback
is a hook that is used to memoize functions, similar to useMemo
, but specifically for functions. It returns a memoized version of the callback function that only changes if one of the dependencies has changed.
Example:
import React, { useCallback, useState } from 'react';
function CounterButton({ onClick }) {
return <button onClick={onClick}>Increment</button>;
}
function Counter() {
const [count, setCount] = useState(0);
const increment = useCallback(() => {
setCount(count + 1);
}, [count]);
return (
<div>
<CounterButton onClick={increment} />
<p>Count: {count}</p>
</div>
);
}
In this example, an increment is a callback function to increment the count state. We use useCallback to memoize this function based on the count state. This ensures that the increment function reference remains stable across renders unless the count state changes.
useContext
useContext
is a hook in React that allows functional components to consume context that has been provided by a parent component.
Structure:
import React, { useContext } from 'react';
const MyContext = React.createContext(defaultValue);
function MyComponent() {
const value = useContext(MyContext);
// Use value in your component
return (
// JSX for component
);
}
- First, you need to create a context using
React.createContext()
. You can optionally pass a default value to the context. This default value will be used when a component does not have a matching provider. - Define your functional component where you want to use useContext.
- Call useContext() and pass the context you created as an argument. This hook returns the current context value for the given context.
Example:
import React, { useContext } from 'react';
const ThemeContext = React.createContext('light');
function ThemedButton() {
const theme = useContext(ThemeContext);
return <button style={{ background: theme }}>Themed Button</button>;
}
function App() {
return (
<div>
<ThemeContext.Provider value="dark">
<ThemedButton />
</ThemeContext.Provider>
</div>
);
}
In this example, ThemedButton component consumes the ThemeContext using useContext. It changes its style based on the current theme provided by the context.
useReducer
useReducer
is a hook in React that is used for state management, similar to useState
, but it's more suitable for managing complex state logic.
Example:
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:
return state;
}
}
function Counter() {
const [state, dispatch] = useReducer(reducer, initialState);
return (
<div>
Count: {state.count}
<button onClick={() => dispatch({ type: 'INCREMENT' })}>Increment</button>
<button onClick={() => dispatch({ type: 'DECREMENT' })}>Decrement</button>
</div>
);
}
Explanation:
- Define a
reducer
function, it takes the current state and an action as arguments and returns the new state based on the action. It's similar to the reducer function in Redux. - Define your functional component(
Counter
) where you want to use useReducer. - Call useReducer() and pass the reducer function and initial state as arguments. This hook returns an array with the current state and a dispatch function.
The counter component uses useReducer
to manage the state of a count. It dispatches actions (INCREMENT and DECREMENT) to update the count based on user interactions with buttons.
These are some of the most commonly used hooks in React applications, but there are many others available. Each hook serves a specific purpose and can help improve the readability, performance, and maintainability of your code.
Discover the art of crafting custom hooks in ReactJS. Click here to dive in!
Posted on May 11, 2024
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.