ReactJS introduced Hooks in version 16.8, revolutionizing the way developers write functional components. Hooks allow you to use state, lifecycle methods, and other React features in functional components, making code more concise, reusable, and easier to maintain. In this article, we’ll explore some of the most widely used React hooks with detailed explanations and examples.
1. useState
The useState
hook is the most commonly used hook in React. It allows you to add state to functional components.
Example: Counter App
import React, { useState } from "react";
function Counter() {
const [count, setCount] = useState(0);
return (
<div>
<p>Current Count: {count}</p>
<button onClick={() => setCount(count + 1)}>Increment</button>
<button onClick={() => setCount(count - 1)}>Decrement</button>
</div>
);
}
What it does: useState
initializes the state variable count
with 0
. The setCount
function updates its value.
2. useEffect
The useEffect
hook lets you perform side effects such as data fetching, DOM manipulation, or subscriptions.
Example: Fetching Data
import React, { useEffect, useState } from "react";
function DataFetcher() {
const [data, setData] = useState([]);
useEffect(() => {
fetch("https://jsonplaceholder.typicode.com/posts")
.then((response) => response.json())
.then((json) => setData(json));
}, []); // Empty dependency array runs the effect once, like componentDidMount
return (
<ul>
{data.map((item) => (
<li key={item.id}>{item.title}</li>
))}
</ul>
);
}
What it does: Runs a side effect (data fetching) when the component mounts.
3. useContext
The useContext
hook provides a way to access data from React’s Context API, avoiding the need for prop drilling.
Example: Theme Context
import React, { createContext, useContext } from "react";
const ThemeContext = createContext("light");
function App() {
return (
<ThemeContext.Provider value="dark">
<ThemedComponent />
</ThemeContext.Provider>
);
}
function ThemedComponent() {
const theme = useContext(ThemeContext);
return <p>The current theme is {theme}.</p>;
}
What it does: Fetches the theme
value from ThemeContext
.
4. useRef
The useRef
hook creates a reference to a DOM element or stores mutable values that persist across renders without causing re-renders.
Example: DOM Manipulation
import React, { useRef } from "react";
function FocusInput() {
const inputRef = useRef(null);
const focusInput = () => {
inputRef.current.focus();
};
return (
<div>
<input ref={inputRef} type="text" />
<button onClick={focusInput}>Focus Input</button>
</div>
);
}
What it does: Directly accesses the DOM element using inputRef
.
5. useReducer
The useReducer
hook is useful for managing complex state logic. It’s an alternative to useState
for situations where state transitions are complex or involve multiple sub-values.
Example: Counter with Reducer
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" })}>+</button>
<button onClick={() => dispatch({ type: "decrement" })}>-</button>
</div>
);
}
What it does: Manages state transitions using the reducer
function.
6. useMemo
The useMemo
hook is used to optimize performance by memoizing expensive computations, avoiding unnecessary recalculations.
Example: Expensive Calculation
import React, { useState, useMemo } from "react";
function ExpensiveCalculation({ num }) {
console.log("Calculating...");
let result = 0;
for (let i = 0; i < 1000000000; i++) {
result += i;
}
return result * num;
}
function App() {
const [count, setCount] = useState(1);
const [multiplier, setMultiplier] = useState(2);
const memoizedResult = useMemo(() => ExpensiveCalculation({ num: multiplier }), [multiplier]);
return (
<div>
<h1>Result: {memoizedResult}</h1>
<button onClick={() => setCount(count + 1)}>Re-render</button>
<button onClick={() => setMultiplier(multiplier + 1)}>Change Multiplier</button>
</div>
);
}
What it does: Prevents recalculating ExpensiveCalculation
unless multiplier
changes.
7. useCallback
The useCallback
hook memoizes functions, preventing unnecessary re-creations during renders, especially useful with React.memo
.
Example: Memoized Callback
import React, { useState, useCallback } from "react";
function Child({ increment }) {
console.log("Child rendered");
return <button onClick={increment}>Increment</button>;
}
const MemoizedChild = React.memo(Child);
function Parent() {
const [count, setCount] = useState(0);
const increment = useCallback(() => setCount((prev) => prev + 1), []);
return (
<div>
<p>Count: {count}</p>
<MemoizedChild increment={increment} />
</div>
);
}
What it does: Prevents increment
from being re-created on every render.
Conclusion
ReactJS hooks have transformed the way developers write functional components, making code more elegant and easier to understand. From managing state with useState
to optimizing performance with useMemo
and useCallback
, each hook serves a specific purpose.