Context API in React: Your Secret Weapon for Global State
The Context API is a part of React, a popular JavaScript library for building user interfaces, that provides a way to manage and share state and data across components in an efficient and organized manner.
It helps solve the problem of “prop drilling” which is the process of passing props (properties) through multiple levels of nested components just to get data from a top-level component to a deeply nested one. Prop drilling can make your codebase harder to maintain and less readable as your application grows in complexity.
Rules for Context API
create Context() → creation
provider → Context provider
consume
Steps
- Create a “context” folder in the src folder then create an AppContext.js file
Here we take a small part of a project to understand the concepts of context API
Create Context
import { createContext} from "react";
//step1
export const AppContext = createContext();
Create Provider
function AppContextProvider({children}) {
// after some time we will see
}
Then go to the index.js file the wrap the <App />
component with <AppContextProvider />
<AppContextProvider>
<App />
</AppContextProvider>
Now we have to create state variables that are passed to their children components. Let’s take an example, a website that used some data like posts, pageNumber, loading, and totalPage in the whole website. Then we have to create the state variables for these data so we can use these data anywhere without “prop drilling”.
import { createContext, useState } from "react";
//step1
export const AppContext = createContext();
export default function AppContextProvider({children}) {
// NEW CODE
// create state variables which are used in context api
const [loading, setLoading] = useState(false);
const [posts, setPosts] = useState([]);
const [page, setPage] = useState(1);
const [totalPages, setTotalPages] = useState(null);
}
Now we have to create a value
that which data are used in any children of AppContext
.
import { createContext, useState } from "react";
//step1
export const AppContext = createContext();
export default function AppContextProvider({children}) {
// create state variables which are used in context api
const [loading, setLoading] = useState(false);
const [posts, setPosts] = useState([]);
const [page, setPage] = useState(1);
const [totalPages, setTotalPages] = useState(null);
// new code
const value = {
posts,
setPosts,
loading,
setLoading,
page,
setPage,
totalPages,
setTotalPages,
};
}
Main things that, how to pass this value
in children component.
import { createContext, useState } from "react";
//step1
export const AppContext = createContext();
export default function AppContextProvider({children}) {
// create state variables which are used in context api
const [loading, setLoading] = useState(false);
const [posts, setPosts] = useState([]);
const [page, setPage] = useState(1);
const [totalPages, setTotalPages] = useState(null);
const value = {
posts,
setPosts,
loading,
setLoading,
page,
setPage,
totalPages,
setTotalPages,
};
// new code
//step2
return <AppContext.Provider value={value}>
{children}
</AppContext.Provider>;
}
From the above part, we miss one thing which is “Data filling”. Here we use a api
to get the data. So we use fetch()
function to fetch the data from the API. The data looks like this:
{
"page": 1,
"pageSize": 5,
"totalPosts": 30,
"totalPages": 6,
"posts": [
{...},
{...},
{...},
{...},
{...}
]
}
Now create an async function to fill the data fetchBlogPosts
import { createContext, useState } from "react";
import { baseUrl } from "../baseUrl";
// baseUrl is a simple file where the link of api is present.
//step1
export const AppContext = createContext();
export default function AppContextProvider({children}) {
// create state variables which are used in context api
const [loading, setLoading] = useState(false);
const [posts, setPosts] = useState([]);
const [page, setPage] = useState(1);
const [totalPages, setTotalPages] = useState(null);
// new code
// filling data
async function fetchBlogPosts(page = 1) {
setLoading(true); // 1st we set true in loading
let url = `${baseUrl}?page=${page}`;
console.log("printing the final URL");
console.log(url);
try{
const result = await fetch(url); // fetch the data from api
const data = await result.json(); // convert the data into json
console.log(data);
setPage(data.page); // set the page
setPosts(data.posts); // set the post
setTotalPages(data.totalPages) // set the total post
}
// handling error part
catch(error) {
console.log("Error in fetching data");
setPage(1);
setPosts([]);
setTotalPages(null);
}
// after completing fetching the data then we set false to loading
setLoading(false);
}
const value = {
posts,
setPosts,
loading,
setLoading,
page,
setPage,
totalPages,
setTotalPages,
fetchBlogPosts // send the function also
};
//step2
return <AppContext.Provider value={value}>
{children}
</AppContext.Provider>;
}
This part is extra :
Create a function to handle the page change
import { createContext, useState } from "react";
import { baseUrl } from "../baseUrl";
// baseUrl is a simple file where the link of api is present.
//step1
export const AppContext = createContext();
export default function AppContextProvider({children}) {
// create state variables which are used in context api
const [loading, setLoading] = useState(false);
const [posts, setPosts] = useState([]);
const [page, setPage] = useState(1);
const [totalPages, setTotalPages] = useState(null);
// filling data
async function fetchBlogPosts(page = 1) {
setLoading(true); // 1st we set true in loading
let url = `${baseUrl}?page=${page}`;
console.log("printing the final URL");
console.log(url);
try{
const result = await fetch(url); // fetch the data from api
const data = await result.json(); // convert the data into json
console.log(data);
setPage(data.page); // set the page
setPosts(data.posts); // set the post
setTotalPages(data.totalPages) // set the total post
}
// handling error part
catch(error) {
console.log("Error in fetching data");
setPage(1);
setPosts([]);
setTotalPages(null);
}
// after completing fetching the data then we set false to loading
setLoading(false);
}
// new code
function handlePageChange(page) {
setPage(page);
fetchBlogPosts(page);
}
const value = {
posts,
setPosts,
loading,
setLoading,
page,
setPage,
totalPages,
setTotalPages,
fetchBlogPosts, // send the function also
handlePageChange
};
//step2
return <AppContext.Provider value={value}>
{children}
</AppContext.Provider>;
}
We created centralized data using Context Provider, so we don’t have to think about How to lift the data or How to drill the data.
We completed two main steps: creation and provider.
Now we have to think “How to consume the data ?”, so the answer is “ HOOK” named “useContext”
Consume Data
This part is very simple, no need to worry about where the data is present because we centralized the data. Here we use
useContext()
hook to consume the data. If a component is used loading data and post data then we use this hook inside that component.import React, { useContext } from 'react' import { AppContext } from '../context/AppContext' const Blogs = () => { const {posts,loading} = useContext(AppContext); console.log("Printing inside blogs component"); console.log(posts); }
We provide the name of the context in
useContext()
likeuseContext(AppContext).
Conclusion
In summary, the Context API in React is used to manage and share global state and data between components efficiently, making your codebase more maintainable, readable, and performant. It simplifies component composition and reduces the complexity of passing props through multiple layers of components, which can be especially beneficial in larger and more complex applications.
Thank you for joining us on this journey through the world of React’s Context API. I hope this guide has been a valuable resource, and I look forward to seeing the amazing applications you create using this essential tool.
Special Thanks to Love Babbar bhaiya 🙏🏻
Happy coding, and keep building!
Subscribe to my newsletter
Read articles from Bidyasagar mohapatra directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by