Context API in React: A Real-Life Analogy and Technical Guide

Featured on Hashnode
Context API in React: A Real-Life Analogy and Technical Guide

Imagine you're at a large family dinner, and everyone needs to know the time. Instead of each person asking individually, a clock is placed in the centre of the table for everyone to see. This clock serves as a shared context for the entire family, eliminating the need for repetitive communication.

In the realm of React applications, the Context API serves a similar purpose. It allows multiple components to access shared data without the need for prop drilling, making your code cleaner and more efficient. This blog will walk you through the Context API, demonstrating its power by building a shopping cart and wishlist feature.

What is Context API 🤔?

The Context API in React is a mechanism for effectively managing state and passing data through the component tree without relying on prop drilling. It is particularly useful when you need to share states or functions between deeply nested components.

Why Use Context API?

  • Avoid Prop Drilling: Context API eliminates the need to pass props through every level of your component tree.

  • Global State Management: Ideal for managing global states such as user authentication, themes, and language settings.

  • Cleaner Code: Enhances code readability and maintainability by reducing the complexity of prop passing.

Setting Up the Context

Before starting anything, you will need to have some pre-requisites:

  1. Set up a React project.

  2. I am using Tailwind CSS for this, so you can also install it.

  3. I am using react-icons library to use icons.

1. Create the Context

First, you need to place a clock on the wall. Similarly, here you have to create a context first with the help of the createContext() function. You can create a separate file for context. I have written context in the same file from where I am going to export.

After declaring the context, you have to provide the context to the rest of your application. This can be done using <ContextName.Provider value={}>{children}</ContextName.Provider>. Wrap your application with the provider component to make the context available to its children.

import React, { createContext, useState,useEffect } from 'react';
// create context
export const customContext = createContext();

const ContextProvider = ({children}) => {
  const [state, setState] = useState(0);
  const [image,setImage ] = useState();
  const [wishlist,setWishlist ] = useState(0);

  // api to fetch one random image
  const api = async()=>{
    const fetchImage = await fetch("https://picsum.photos/300/300");
    setImage(fetchImage.url);
  }
  useEffect(()=>{
    api();
  },[]);

  return (
    <customContext.Provider value={{state, setState,image,wishlist,setWishlist}}>
      {children}
    </customContext.Provider>
  );
};

export default ContextProvider;

2. App.js file to decide the routes.

This is the main file that will decide the route. I am using react-router-dom library to route in my app.

jsxCopy code// App.js
import React from 'react';
import { BrowserRouter as Router, Route, Routes } from 'react-router-dom';
import UseCon from './ContextProvider';
import GetCon from './GetCon';
import Cart from './Cart';
import Wishlist from './Wishlist';

function App() {
  return (
    <UseCon>
      <Router>
        <Routes>
          <Route path="/" element={<GetCon />} />
          <Route path="/cart" element={<Cart />} />
          <Route path="/wishlist" element={<Wishlist />} />
        </Routes>
      </Router>
    </UseCon>
  );
}

export default App;

Consuming the Context

Access the context value in your components using the useContext(ContextName)( hook. You can access them globally by destructuring the context value.

ContextConsumer Component

This component fetches an image from an API and displays it. It also uses the context to update the cart and wishlist values. This component has an image, two buttons, two links and a wishlist icon.

import {useContext} from 'react'
import { customContext } from './ContextProvider';
import { Link } from 'react-router-dom';
import { FiHeart } from 'react-icons/fi';
import { FaCircle } from 'react-icons/fa';

export default function ContextConsumer({children}) {
   const { state, setState, image, wishlist, setWishlist} = useContext(customContext);
  return (
    <div className='flex flex-col justify-center items-center gap-8'>
      <h1 className='font-bold text-3xl text-center'>Demonstrating CONTEXT API</h1>

      <div className='flex justify-center items-center flex-col gap-2 '>
        <div className='card border-4 relative border-gray-800 rounded-lg shadow-2xl h-[300px] w-[300px]'>
          {image && <img src={image} alt='image is here'/>}
          <FiHeart className={`absolute top-1 right-1 z-20 cursor-pointer  ${wishlist ? 'fill-yellow-50 ':'fill-none  hover:fill-none'} `} onClick={()=>setWishlist((prev)=>!prev)} />
        </div>

        <div className="flex justify-center gap-2">
          <button className='p-2 rounded-sm bg-slate-600 shadow-lg text-white font-semibold' onClick={()=>setState((prev)=>prev+1)}>Add to cart ({state})</button>
          <button disabled={!state} className='p-2 rounded-sm bg-slate-600 shadow-lg disabled:bg-slate-400 disabled:cursor-not-allowed text-white font-semibold' onClick={()=>setState((prev)=>prev-1)}>Remove from cart </button>
        </div>

        <div className="flex gap-2 ">
          <Link to={'/cart'} className='underline font-semibold'>Go to Cart</Link>
          <Link to={'/wishlist'} className='underline relative font-semibold'>Wishlist
            {wishlist ? 
            <FaCircle size={8} fill='red' className=' fill-red-900 animate-pulse absolute top-0 -right-2'/> : null}
          </Link>
        </div>

        {children}
    </div>

  </div>
  )
}

Cart Component

This component consumes the context to display the current cart value. As the cart changes its state, the same state will be reflected here.

import {useContext} from 'react'
import { customContext } from './ContextProvider';
import { Link } from 'react-router-dom';
import { BiArrowBack } from 'react-icons/bi';

export default function Cart() {
   const { state , image} = useContext(customContext);
   return(
   <div className='flex gap-4 flex-col items-start'>
    <h1 className='font-bold text-xl '>{state ? `Your cart 🛒 value is ${state}:` :`Your cart is empty`}</h1>
    {state ? (
      <div className="flex gap-2 bg-slate-600 p-2 shadow-lg rounded-md max-w-[300px]">
        <div className='card border-4  border-yellow-50 rounded-lg shadow-2xl h-min w-fit'>
          {image && <img src={image} alt='imageishere'/>}
        </div>
        <div className=" flex flex-col text-yellow-50 gap-1"><p className='font-medium text-base leading-[20px]'>This is the Dummy image, coming from api.</p>
          <span className='text-sm'>Quantity: {state}</span>
        </div>
      </div>
    ):
    null}
    <Link to={'/'} className='hover:underline font-semibold flex items-center gap-1'><BiArrowBack/>Go back</Link>
   </div>
   )
}

Wishlist Component

This component consumes the context to display the wishlist state. If the wishlist is empty, it will reflect the same state.

import {useContext} from 'react'
import { customContext } from './ContextProvider';
import { Link } from 'react-router-dom';
import { IoClose } from 'react-icons/io5';
import { BiArrowBack } from 'react-icons/bi';

export default function Wishlist() {
   const { image, wishlist, setWishlist} = useContext(customContext);
   return(
    <div className='flex gap-4 flex-col items-start'>
      <h1 className='font-bold text-xl '>{wishlist ? `Your Wishlist✨` :`Oopss, you didn't made a wish till now:(`}</h1>
      {wishlist ? (
        <div className="flex gap-2 bg-slate-600 p-2 shadow-lg rounded-md max-w-[300px]">
          <div className='card border-4  border-yellow-50 rounded-lg shadow-2xl h-min w-fit'>
            {image && <img src={image} alt='imageishere'/>}
          </div>
          <div className=" flex relative flex-col text-yellow-50 gap-1"><p className='font-medium text-base leading-[20px]'>This is the Dummy image, coming from api.</p>
            <button title='Remove from wishlist' className='text-sm absolute bottom-1 p-1 bg-yellow-50 hover:bg-amber-100 font-semibold text-slate-600 rounded-sm flex gap-1 items-end justify-center' onClick={()=>setWishlist(prev=>!prev)}>Remove <IoClose/></button>
          </div>
        </div>
      ):null}
      <Link to={'/'} className='hover:underline font-semibold flex gap-1 items-center'><BiArrowBack/> Go back</Link>
    </div>
   )
}

So, what are you waiting for?

The Context API in React is a powerful tool for managing global state. It simplifies the process of sharing data between components, avoiding the cumbersome prop-drilling method. By understanding and using the Context API, you can make your React applications more efficient and maintainable.

Check out the whole source code in this repository: here . Don't forget to ⭐ the repo.

Do you want to see it live? Head over to Shopping Cart and see the magic✨

In this example, we built a shopping cart and wishlist feature using Context API. We demonstrated how to create a context, provide it to the component tree, and consume it in various components. This approach helps keep our code clean and organized while efficiently managing the state across the application.

Feel free to experiment with this example and explore more advanced.

Want to read more?

Find me on this socials. I would love to connect with you:

Have a wonderful day🌻!