React Hooks are functions that let you use state and other React features in functional components. They make your code cleaner, reusable, and easier to manage. This blog explains the key hooks and how to use them in simple words.
Before hooks, only class components could have state and lifecycle methods. Hooks allow functional components to have state, side-effects, context, and more.
The `useState` hook allows you to add state to your functional components.
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>
);
}Explanation: `useState(0)` initializes `count` to 0. `setCount` updates the state. Every time you click the button, React re-renders the component with the new state.
The `useEffect` hook lets you run side-effects in functional components, like fetching data, updating the DOM, or subscribing to events.
import React, { useState, useEffect } from 'react';
function Timer() {
const [seconds, setSeconds] = useState(0);
useEffect(() => {
const interval = setInterval(() => {
setSeconds(s => s + 1);
}, 1000);
return () => clearInterval(interval); // cleanup
}, []);
return <p>Seconds: {seconds}</p>;
}Explanation: The empty dependency array `[]` makes this effect run only once when the component mounts. The cleanup function stops the timer when the component unmounts.
The `useContext` hook lets you access React context in functional components without using `Context.Consumer`.
import React, { createContext, useContext } from 'react';
const ThemeContext = createContext('light');
function ThemedButton() {
const theme = useContext(ThemeContext);
return <button className={theme}>Click me</button>;
}You can create your own hooks to reuse logic between components. Custom hooks always start with `use`.
import { useState, useEffect } from 'react';
function useWindowWidth() {
const [width, setWidth] = useState(window.innerWidth);
useEffect(() => {
const handleResize = () => setWidth(window.innerWidth);
window.addEventListener('resize', handleResize);
return () => window.removeEventListener('resize', handleResize);
}, []);
return width;
}
function App() {
const width = useWindowWidth();
return <p>Window width: {width}</p>;
}`useMemo` memoizes expensive computations. It recalculates the value only when dependencies change, saving unnecessary recalculations.
import React, { useMemo, useState } from 'react';
function ExpensiveCalculation({ number }) {
const factorial = useMemo(() => {
console.log('Calculating factorial...');
const compute = (n) => (n <= 1 ? 1 : n * compute(n - 1));
return compute(number);
}, [number]);
return <p>Factorial: {factorial}</p>;
}`useCallback` memoizes a function reference. It is useful when passing functions to child components to prevent unnecessary re-renders.
import React, { useState, useCallback } from 'react';
function Button({ onClick }) {
console.log('Button rendered');
return <button onClick={onClick}>Click me</button>;
}
function App() {
const [count, setCount] = useState(0);
const handleClick = useCallback(() => {
setCount(c => c + 1);
}, []);
return (
<div>
<p>Count: {count}</p>
<Button onClick={handleClick} />
</div>
);
}`useRef` allows you to persist a value across renders without causing a re-render. It is also commonly used to reference DOM elements.
import React, { useRef } from 'react';
function FocusInput() {
const inputRef = useRef(null);
return (
<div>
<input ref={inputRef} placeholder="Type something" />
<button onClick={() => inputRef.current.focus()}>Focus Input</button>
</div>
);
}`useReducer` is useful for managing complex state logic. It works like Redux but is local to a component.
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>
<p>Count: {state.count}</p>
<button onClick={() => dispatch({ type: 'increment' })}>+</button>
<button onClick={() => dispatch({ type: 'decrement' })}>-</button>
</div>
);
}`useLayoutEffect` is similar to useEffect but runs synchronously after all DOM mutations, before the browser paints. Useful for measuring layout or manipulating the DOM.
import React, { useLayoutEffect, useRef, useState } from 'react';
function Box() {
const boxRef = useRef(null);
const [height, setHeight] = useState(0);
useLayoutEffect(() => {
setHeight(boxRef.current.clientHeight);
}, []);
return (
<div>
<div ref={boxRef} style={{ height: '100px', background: 'lightblue' }}></div>
<p>Box height: {height}px</p>
</div>
);
}`useImperativeHandle` customizes the instance value that is exposed when using `ref`. Useful when exposing functions from child to parent.
import React, { useImperativeHandle, useRef, forwardRef } from 'react';
const FancyInput = forwardRef((props, ref) => {
const inputRef = useRef();
useImperativeHandle(ref, () => ({
focus: () => {
inputRef.current.focus();
}
}));
return <input ref={inputRef} />;
});
function App() {
const fancyRef = useRef();
return (
<div>
<FancyInput ref={fancyRef} />
<button onClick={() => fancyRef.current.focus()}>Focus Fancy Input</button>
</div>
);
}• Only call hooks at the top level of a component or custom hook.
• Only call hooks from React functions (functional components or custom hooks).
• Do not call hooks inside loops, conditions, or nested functions.
React Hooks revolutionized the way we write React components. They allow functional components to be powerful, stateful, and capable of side-effects, making React code cleaner, reusable, and easier to maintain.