Understanding the Problem
In this tutorial, we need to implement React Context in a horoscope application. We need to:
- Create a Context using
createContext - Set up a Provider to wrap our application
- Consume the context in the Detail component
This will allow us to share data (horoscope information) across components without prop drilling.
Devising a Plan
- Create a context directory and file for our HoroscopeContext
- Create the context using React's createContext
- Wrap our App with the HoroscopeContext.Provider in main.jsx
- Pass horoscope data through the Provider's value prop
- Consume the context in our Detail component using useContext
- Display the horoscope information in the Detail component
Carrying Out the Plan
Step 1: Create the Context File
First, we need to create a directory called context in the src folder and create a file called HoroscopeContext.jsx inside it.
File location: src/context/HoroscopeContext.jsx
import { createContext } from 'react';
export const HoroscopeContext = createContext();
This creates our context using React's createContext function. Think of this as creating a special channel through which data can flow across your component tree.
Step 2: Set Up the Provider in main.jsx
Now, we need to modify main.jsx to import our context and wrap the App component with the Provider.
File location: src/main.jsx
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import './index.css';
import { HoroscopeContext } from './context/HoroscopeContext';
ReactDOM.createRoot(document.getElementById('root')).render(
<React.StrictMode>
<HoroscopeContext.Provider value={{ sign: "Leo" }}>
<App />
</HoroscopeContext.Provider>
</React.StrictMode>
);
Here, we're wrapping our entire App with the HoroscopeContext.Provider and providing an initial value of { sign: "Leo" }. This is like setting up a broadcast station that will make this data available to any component that wants to tune in.
Step 3: Consume the Context in the Detail Component
Now, let's modify the Detail component to consume our context.
File location: src/components/Detail.jsx
import { useContext } from 'react';
import { HoroscopeContext } from '../context/HoroscopeContext';
const Detail = () => {
const horoscopesObj = useContext(HoroscopeContext);
return (
<div className='details'>
<img
src='https://upload.wikimedia.org/wikipedia/commons/e/e1/FullMoon2010.jpg'
alt=''
/>
<h2>{horoscopesObj.sign}</h2>
<h4>Element: </h4>
<h4>Traits: </h4>
</div>
);
};
export default Detail;
In this step, we import useContext from React and our HoroscopeContext. We then use the useContext hook to access the context value. This is like tuning in to receive the broadcast from our Provider.
We display the sign from our context in the h2 element, replacing "Current Sign Name" with the actual sign (Leo).
Looking Back and Extending
We've successfully implemented React Context in our horoscope application! Let's review what we've done:
- Created a context using
createContext - Set up a Provider to wrap our application
- Consumed the context in the Detail component
Further Improvements
Now that we have the basic context set up, here are some ways we could improve our application:
Display More Horoscope Information
We can enhance our context to include more information from our horoscope data.
Updated main.jsx:
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import './index.css';
import { HoroscopeContext } from './context/HoroscopeContext';
import horoscopeObj from './data/horoscopes';
ReactDOM.createRoot(document.getElementById('root')).render(
<React.StrictMode>
<HoroscopeContext.Provider value={{
sign: "Leo",
currentHoroscope: horoscopeObj["Leo"]
}}>
<App />
</HoroscopeContext.Provider>
</React.StrictMode>
);
Updated Detail.jsx:
import { useContext } from 'react';
import { HoroscopeContext } from '../context/HoroscopeContext';
const Detail = () => {
const { currentHoroscope } = useContext(HoroscopeContext);
return (
<div className='details'>
<img
src={currentHoroscope.backgroundImg}
alt={currentHoroscope.name}
/>
<h2>{currentHoroscope.name}</h2>
<h4>Element: {currentHoroscope.element}</h4>
<h4>Traits: {currentHoroscope.traits}</h4>
</div>
);
};
export default Detail;
Implement Sign Selection
We could also implement functionality to change the selected sign when clicking on the navbar items. This would require using React's useState hook alongside our context.
Create a Custom Provider Component
For more complex state management, we might want to create a custom Provider component:
// src/context/HoroscopeContext.jsx
import { createContext, useState } from 'react';
import horoscopeObj from '../data/horoscopes';
export const HoroscopeContext = createContext();
export const HoroscopeProvider = ({ children }) => {
const [currentSign, setCurrentSign] = useState("Leo");
return (
<HoroscopeContext.Provider
value={{
sign: currentSign,
currentHoroscope: horoscopeObj[currentSign],
setCurrentSign
}}
>
{children}
</HoroscopeContext.Provider>
);
};
And then in main.jsx:
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import './index.css';
import { HoroscopeProvider } from './context/HoroscopeContext';
ReactDOM.createRoot(document.getElementById('root')).render(
<React.StrictMode>
<HoroscopeProvider>
<App />
</HoroscopeProvider>
</React.StrictMode>
);
Real-World Applications
React Context is widely used in real-world applications for scenarios like:
- Theme Management: Light/dark mode toggling across an entire application
- User Authentication: Sharing user login state throughout an app
- Language Selection: Implementing internationalization (i18n)
- Shopping Carts: Maintaining cart state across multiple pages/components
Context API is especially useful for data that is considered "global" for a tree of React components and when you want to avoid "prop drilling" (passing props through many levels of components).
However, for complex state management with frequent updates, you might want to consider using more specialized state management libraries like Redux or Zustand alongside Context.