React Js

6.React Hooks & Context API Explained with Examples | useState, useEffect, useContext

🚀 Mastering React Hooks and Context API in Functional Components

React Hooks revolutionized how we write components by enabling state and side effects in functional components. In this guide, we’ll explore key React Hooks: useState, useEffect, useContext, cleanup functions, and building global state via Context. We’ll also demonstrate a login/logout flow with context updates.

🔹 What are React Hooks?

Hooks are functions that let you “hook into” React state and lifecycle features from function components. Introduced in React 16.8, Hooks eliminate the need for class components while simplifying code reuse and logic separation.

🧠 useState Hook

The useState hook lets you add local state to function components. It returns an array with the current state and a function to update it.

import React, { useState } from 'react';

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

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

You can also use multiple useState declarations:

function ExampleWithManyStates() {
  const [name, setName] = useState("Alice");
  const [phone, setPhone] = useState("123-4567");
  const [todos, setTodos] = useState([{ text: 'Learn Hooks' }]);
}

🧪 useEffect Hook

The useEffect hook allows you to perform side effects in function components, similar to componentDidMount, componentDidUpdate, and componentWillUnmount in class components.

Here’s a simple useEffect example:

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

function App() {
  const [value, setValue] = useState('blogs');

  useEffect(() => {
    console.log('You Clicked Me!');
  });

  return (
    <>
      <button onClick={() => setValue('blogs')}>Blog Post</button>
      <button onClick={() => setValue('participants')}>Participants</button>
      <button onClick={() => setValue('feedback')}>Feedback</button>
      <h1>{value}</h1>
    </>
  );
}

🧹 Limiting Execution with Dependencies

If you want useEffect to run only once (like componentDidMount), pass an empty dependency array:

useEffect(() => {
  console.log('Runs only on mount');
}, []);

If you want it to run on specific state changes:

useEffect(() => {
  console.log('Feeds updated');
}, [feeds]);

♻️ Cleanup with useEffect

Some effects (like timers or subscriptions) need cleanup to avoid memory leaks.

import { useState, useEffect } from "react";

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

  useEffect(() => {
    const timer = setTimeout(() => {
      setCount((prev) => prev + 1);
    }, 1000);

    return () => clearTimeout(timer);
  }, []);

  return <h1>I've rendered {count} times!</h1>;
}

🌐 Fetching Data with useEffect

// services/list.js
export function getList() {
  return fetch('https://gorest.co.in/public/v1/posts')
    .then(data => data.json());
}
import React, { useEffect, useState } from 'react';
import { getList } from './services/list';

function App() {
  const [list, setList] = useState([]);

  useEffect(() => {
    let mounted = true;
    getList().then(items => {
      if (mounted) {
        setList(items.data);
      }
    });
    return () => (mounted = false);
  }, []);

  return (
    <div>
      <h1>My List</h1>
      <ul>
        {list.map(item => (
          <li key={item.id}><h2>{item.title}</h2></li>
        ))}
      </ul>
    </div>
  );
}

🧵 useContext Hook

Context lets you share state across components without passing props manually. The useContext hook simplifies consuming context.

🔧 Creating Context

import { createContext } from 'react';
const MyContext = createContext('Default Value');

📤 Providing Context

function App() {
  const value = "My Context Value";
  return (
    <MyContext.Provider value={value}>
      <MyComponent />
    </MyContext.Provider>
  );
}

📥 Consuming Context

function MyComponent() {
  const value = useContext(MyContext);
  return <span>{value}</span>;
}

🚫 Prop Drilling vs useContext

// Without context (prop drilling)
function Application() {
  const userName = "John Smith";
  return <Layout userName={userName} />;
}

function Layout({ userName }) {
  return (
    <>
      <Header userName={userName} />
      <main>Main content</main>
    </>
  );
}
// With context
const UserContext = createContext("Unknown");

function Application() {
  return (
    <UserContext.Provider value="John Smith">
      <Layout />
    </UserContext.Provider>
  );
}

function UserInfo() {
  const userName = useContext(UserContext);
  return <span>{userName}</span>;
}

🏗️ Full useContext Example

const employeeContext = React.createContext();

function App() {
  const [employee, setEmployee] = useState({
    Id: 101,
    Name: "Karim",
    Location: "Kolkata",
    Salary: 12345
  });

  return (
    <employeeContext.Provider value={employee}>
      <Employee />
      <Salary />
    </employeeContext.Provider>
  );
}

function Employee() {
  const context = useContext(employeeContext);
  return (
    <div>
      <p>ID: {context.Id}</p>
      <p>Name: {context.Name}</p>
    </div>
  );
}

🆙 Updating Context via useState

const ThemeContext = React.createContext(null);

function App() {
  const [color, setColor] = useState("Green");

  return (
    <ThemeContext.Provider value={{ color, setColor }}>
      <ChangeColor />
    </ThemeContext.Provider>
  );
}

function ChangeColor() {
  const { color, setColor } = useContext(ThemeContext);

  const toggleColor = () => {
    setColor(color === "Green" ? "Red" : "Green");
  };

  return (
    <button onClick={toggleColor}>Change Color</button>
  );
}

🔐 Authentication Example with useContext

Let’s create a login/logout authentication system using context.

// AuthContext.js
import React from 'react';
const AuthContext = React.createContext({
  auth: null,
  login: () => {},
  logout: () => {},
});
export default AuthContext;
// App.js
import React, { useState } from 'react';
import Login from './Login';
import Logout from './Logout';
import AuthContext from './AuthContext';

function App() {
  const [auth, setAuth] = useState(false);
  const login = () => setAuth(true);
  const logout = () => setAuth(false);

  return (
    <AuthContext.Provider value={{ auth, login, logout }}>
      <p>{auth ? "You are logged in" : "Please log in"}</p>
      <Login />
      <Logout />
    </AuthContext.Provider>
  );
}
// Login.js
import React, { useContext } from 'react';
import AuthContext from './AuthContext';

function Login() {
  const auth = useContext(AuthContext);
  return <button onClick={auth.login}>Login</button>;
}
// Logout.js
import React, { useContext } from 'react';
import AuthContext from './AuthContext';

function Logout() {
  const auth = useContext(AuthContext);
  return <button onClick={auth.logout}>Logout</button>;
}

✅ Conclusion

React Hooks such as useState, useEffect, and useContext offer powerful ways to manage component logic and state without relying on classes. With the Context API and custom hooks, you can design scalable applications that minimize boilerplate and eliminate prop drilling. By combining these hooks, you can build modern, maintainable, and performant React apps.

Leave a Reply

Your email address will not be published. Required fields are marked *