React

Learn React Hooks: A Practical Guide with Examples

Arun Tyagi
September 13, 2025
14 min read
#React#Hooks#useEffect#useState#useMemo#useCallback

What Are Hooks?

Hooks are functions that let you use React features in function components. They replace many class patterns with simpler, reusable logic.

useState

Manage local component state.

"use client";
import { useState } from 'react';

export default function Counter() {
  const [count, setCount] = useState(0);
  return (
    
  );
}

useEffect

Handle side effects like fetching, subscriptions, and timers.

"use client";
import { useEffect, useState } from 'react';

export default function FetchUser() {
  const [user, setUser] = useState(null);
  useEffect(() => {
    let isMounted = true;
    fetch('/api/user').then(r => r.json()).then(data => {
      if (isMounted) setUser(data);
    });
    return () => { isMounted = false };
  }, []);
  return 
{JSON.stringify(user, null, 2)}
; }

useMemo

Memoize expensive calculations.

import { useMemo } from 'react';

function sumLargeArray(values) {
  return values.reduce((a, b) => a + b, 0);
}

export default function Stats({ values }) {
  const total = useMemo(() => sumLargeArray(values), [values]);
  return 
Total: {total}
; }

useCallback

Memoize functions to avoid unnecessary re-renders in children.

import { useCallback, useState } from 'react';

export default function List() {
  const [items, setItems] = useState([1,2,3]);
  const remove = useCallback((id) => setItems(xs => xs.filter(x => x !== id)), []);
  return items.map(id => (
    
  ));
}

function Row({ id, onRemove }) {
  return 
}

useRef

Hold mutable values or access DOM nodes.

import { useRef } from 'react';

export default function FocusInput() {
  const inputRef = useRef(null);
  return (
    <>
      
      
    
  );
}

useContext

Consume values from React context without prop drilling.

import { createContext, useContext } from 'react';

const ThemeContext = createContext('light');

export default function App() {
  return (
    
      
    
  );
}

function Toolbar() {
  const theme = useContext(ThemeContext);
  return 
Theme: {theme}
; }

useReducer

Manage complex state transitions.

import { useReducer } from 'react';

function reducer(state, action) {
  switch (action.type) {
    case 'inc':
      return { count: state.count + 1 };
    case 'dec':
      return { count: state.count - 1 };
    default:
      return state;
  }
}

export default function Counter() {
  const [state, dispatch] = useReducer(reducer, { count: 0 });
  return (
    
{state.count}
); }

useId

Generate stable IDs for accessibility.

import { useId } from 'react';

export default function Field() {
  const id = useId();
  return (
    <>
      
      
    
  );
}

useLayoutEffect

Like useEffect but fires synchronously after DOM mutations. Use sparingly.

import { useLayoutEffect, useRef, useState } from 'react';

export default function Measure() {
  const ref = useRef(null);
  const [w, setW] = useState(0);
  useLayoutEffect(() => {
    setW(ref.current?.offsetWidth ?? 0);
  });
  return 
Width: {w}
; }

useImperativeHandle

Customize the instance value exposed by ref in parent components.

import { forwardRef, useImperativeHandle, useRef } from 'react';

const Input = forwardRef(function Input(_props, ref) {
  const innerRef = useRef(null);
  useImperativeHandle(ref, () => ({ focus: () => innerRef.current?.focus() }));
  return 
});

export default function Parent() {
  const ref = useRef(null);
  return ;
}

useDeferredValue & useTransition

Defer or mark updates as non-urgent to keep the UI responsive.

import { useDeferredValue, useState, useTransition } from 'react';

export default function Search() {
  const [query, setQuery] = useState('');
  const [isPending, startTransition] = useTransition();
  const deferred = useDeferredValue(query);
  const results = expensiveFilter(deferred);
  
  function onChange(e) {
    const value = e.target.value;
    startTransition(() => setQuery(value));
  }
  
  return ;
}

Custom Hooks

Extract reusable logic:

import { useEffect, useState } from 'react';

function useWindowWidth() {
  const [w, setW] = useState(0);
  useEffect(() => {
    const onResize = () => setW(window.innerWidth);
    onResize();
    window.addEventListener('resize', onResize);
    return () => window.removeEventListener('resize', onResize);
  }, []);
  return w;
}

export default function Component() {
  const width = useWindowWidth();
  return 
Width: {width}
; }

Best Practices

  • Place hooks at the top level, never inside conditions or loops
  • Prefer useReducer for complex state updates
  • Memoize props for heavy child components with useMemo/useCallback
  • Use useEffect for effects, not for deriving state from props