AI Reading
Quick summary of this article
React Hooks, introduced in React 16.8, let you use state and lifecycle features in functional components without needing classes. This guide covers the essential hooks—useState for local state, useEffect for side effects, and useContext for sharing data across components—along with practical examples like data fetching and a login/logout system.
- useState adds local state to functional components; it returns the current state value and an update function, and you can use multiple useState calls for different pieces of state.
- useEffect handles side effects like logging, timers, or API calls. Passing an empty dependency array
[]makes it run only once (like componentDidMount), while specific dependencies trigger it only when those values change. - Cleanup functions inside useEffect (returned from the effect) help prevent memory leaks by clearing timers, subscriptions, or aborting async operations when the component unmounts.
- useContext eliminates prop drilling by letting any component in a tree access a shared context value directly, without passing props through intermediate components.
- Context can be dynamic: by pairing useContext with useState, you can create global state (like theme colors or authentication status) that updates and re-renders all consuming components automatically.
🚀 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.
