React  

React Hooks Tutorial: Practical Guide with Real Examples for Beginners & Developers

Introduction

React Hooks are a powerful feature that lets developers use state, side effects, context, and more in functional components without writing a class. Hooks were introduced in React 16.8 and are now the standard way to write modern React apps.

What are Hooks?

Hooks are functions that allow you to "hook into" React features. They make component logic simpler, promote reusability, and remove the confusion surrounding class lifecycle methods.

Commonly Used Hooks with Practical Examples

1. useState: lets you add and manage data in your component, such as a counter or input.

import React, { useState } from 'react';

function Counter() {
  const [count, setCount] = useState(0); // Start with 0

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>Click me</button>
    </div>
  );
}

2. useEffect: Runs code automatically when the component loads or updates. It is great for fetching data.

import React, { useState, useEffect } from 'react';

function UserProfile({ userId }) {
  const [user, setUser] = useState(null);

  useEffect(() => {
    fetch(`/api/users/${userId}`)
      .then(res => res.json())
      .then(data => setUser(data));
  }, [userId]); // Runs again only when userId changes

  return user ? <div>{user.name}</div> : <p>Loading...</p>;
}

3. useRef: helps you keep a reference to an element or value without causing re-renders.

import React, { useRef } from 'react';

function TextInputFocus() {
  const inputRef = useRef(null);

  const handleClick = () => {
    inputRef.current.focus(); // Focuses the input box
  };

  return (
    <>
      <input ref={inputRef} type="text" />
      <button onClick={handleClick}>Focus Input</button>
    </>
  );
}

4. useContext: Lets you use data that is shared across components, such as theme or user info, easily.

// ThemeContext.js
import { createContext } from 'react';
export const ThemeContext = createContext('light');

// App.js
import React, { useContext } from 'react';
import { ThemeContext } from './ThemeContext';

function ThemedButton() {
  const theme = useContext(ThemeContext);

  return <button className={theme}>I'm a {theme} button</button>;
}

5. useMemo: Saves the result of a calculation so it won’t run again unless needed.

import React, { useMemo } from 'react';

function ExpensiveCalculation({ number }) {
  const result = useMemo(() => {
    console.log('Calculating...');
    return number * 2;
  }, [number]); // Only recalculates if number changes

  return <p>Result: {result}</p>;
}

6. useCallback: Saves a function so it doesn’t get made again each time the component updates.

import React, { useState, useCallback } from 'react';

function Button({ onClick, label }) {
  console.log("Rendering:", label);
  return <button onClick={onClick}>{label}</button>;
}

function App() {
  const [count, setCount] = useState(0);

  const increment = useCallback(() => {
    setCount(prev => prev + 1);
  }, []);

  return (
    <div>
      <p>Count: {count}</p>
      <Button onClick={increment} label="Increment" />
    </div>
  );
}

Lifecycle Equivalents with useEffect

React Hooks replace class-based lifecycle methods with a clearer syntax by using useEffect. Here’s how they compare:

Step 1. componentDidMount  

Runs once when the component loads for the first time.  

Use: useEffect(() => { ... }, [])  

Step 2. componentDidUpdate  

Runs every time a specific state or prop value changes.  

Use: useEffect(() => { ... }, [dependency])  

Step 3. componentWillUnmount  

Runs when the component is about to be removed, handling cleanup tasks.

useEffect(() => {
  return () => {
    // cleanup code
  };
}, []);

Rules of Hooks

  • Always call Hooks at the top of your function.
  • Only call Hooks from React function components or custom Hooks.

Creating a Custom Hook

Custom Hooks are functions that let you extract and reuse component logic. They help keep your code clean by moving repeated logic out of components. You can use built-in Hooks like useState or useEffect within them.

// Custom Hook: useLocalStorage
import { useState, useEffect } from 'react';

function useLocalStorage(key, initialValue) {
  const [value, setValue] = useState(() => {
    return localStorage.getItem(key) || initialValue;
  });

  useEffect(() => {
    localStorage.setItem(key, value);
  }, [key, value]);

  return [value, setValue];
}

// Usage in a component
function UserSettings() {
  const [username, setUsername] = useLocalStorage("username", "Guest");

  return (
    <div>
      <p>Hello, {username}</p>
      <input value={username} onChange={e => setUsername(e.target.value)} />
    </div>
  );
}

Common Mistakes

  • Forgetting the dependency array in useEffect can lead to problems. 
  • Updating state inside useEffect without the right dependencies can create endless loops. 
  • Using useMemo and useCallback too often without a genuine need for better performance can be an issue.

Conclusion

React Hooks offer a simple and effective way to manage state and lifecycle in functional components. With Hooks, you write less boilerplate code. Components become easier to understand and reuse. Your app runs better with optimized rendering.