Introduction to React Context API | React JS Tutorial for Beginners ๐๐
As our React apps grow bigger, passing data from a parent component down to a deeply nested
child โ through component after component that doesn't even use that data โ becomes messy.
This problem is called prop drilling, and React gives us a clean built-in solution for it:
the Context API.
In this React Context API tutorial, we will learn:
createContext()Provider componentuseContext hookWhat is Prop Drilling?
Imagine App has some data that Sidebar → Menu → MenuItem needs. Normally, you'd
pass that data as a prop through every single component in between โ even though
Sidebar and Menu don't actually use it themselves. This chain of passing props
down just to reach a deeply nested child is called prop drilling, and it makes code
harder to read and maintain as the component tree grows.
What is the React Context API?
The React Context API lets you share data โ like a logged-in user, theme, or language preference โ across the entire component tree without passing props manually at every level. Think of it as a "global store" for a specific piece of data that any component can plug into, no matter how deeply nested it is.
---Step 1: Create a Context
We use React's createContext() function to create a new context. Let's create a
ThemeContext.js file for our example.
import { createContext } from "react";
// Create a Context with a default value
const ThemeContext = createContext("light");
export default ThemeContext;
Step 2: Wrap Your App with the Provider
Every context comes with a Provider component. Wrapping any part of your component
tree with it makes the value available to every component inside it โ no matter how deep.
import React, { useState } from "react";
import ThemeContext from "./ThemeContext";
import Toolbar from "./Toolbar";
function App() {
const [theme, setTheme] = useState("light");
return (
<ThemeContext.Provider value={{ theme, setTheme }}>
<div className="container my-4">
<h2 className="text-center mb-4">React Context API Demo ๐</h2>
<Toolbar />
</div>
</ThemeContext.Provider>
);
}
export default App;
Step 3: Read Context Value with useContext
Instead of passing theme down through props, any nested component can directly
grab it using the useContext hook. Here, Toolbar doesn't even use theme
itself โ it's the child, ThemedButton, that needs it, and it reads it directly.
import React from "react";
import ThemedButton from "./ThemedButton";
function Toolbar() {
// Notice: no props passed down here at all
return (
<div className="d-flex justify-content-center">
<ThemedButton />
</div>
);
}
export default Toolbar;
import React, { useContext } from "react";
import ThemeContext from "./ThemeContext";
function ThemedButton() {
const { theme, setTheme } = useContext(ThemeContext);
const toggleTheme = () => {
setTheme(theme === "light" ? "dark" : "light");
};
return (
<button
className={`btn ${theme === "light" ? "btn-light" : "btn-dark"}`}
onClick={toggleTheme}
>
Current Theme: {theme} (click to toggle)
</button>
);
}
export default ThemedButton;
Step 4: Full Working Example
Here are all three files together, showing the complete flow โ createContext →
Provider → useContext.
// ThemeContext.js
import { createContext } from "react";
const ThemeContext = createContext("light");
export default ThemeContext;
// App.js
import React, { useState } from "react";
import ThemeContext from "./ThemeContext";
import Toolbar from "./Toolbar";
function App() {
const [theme, setTheme] = useState("light");
return (
<ThemeContext.Provider value={{ theme, setTheme }}>
<div className="container my-4">
<h2 className="text-center mb-4">React Context API Demo ๐</h2>
<Toolbar />
</div>
</ThemeContext.Provider>
);
}
export default App;
// Toolbar.js
import React from "react";
import ThemedButton from "./ThemedButton";
function Toolbar() {
return (
<div className="d-flex justify-content-center">
<ThemedButton />
</div>
);
}
export default Toolbar;
// ThemedButton.js
import React, { useContext } from "react";
import ThemeContext from "./ThemeContext";
function ThemedButton() {
const { theme, setTheme } = useContext(ThemeContext);
const toggleTheme = () => {
setTheme(theme === "light" ? "dark" : "light");
};
return (
<button
className={`btn ${theme === "light" ? "btn-light" : "btn-dark"}`}
onClick={toggleTheme}
>
Current Theme: {theme} (click to toggle)
</button>
);
}
export default ThemedButton;
Props vs Context API
| Aspect | Props | Context API |
|---|---|---|
| Data flow | Passed manually, level by level | Available directly to any nested component |
| Best for | Parent-to-direct-child communication | Global-ish data: theme, auth user, language, cart |
| Downside | Prop drilling in deep trees | Overuse can make data flow harder to trace |
Frequently Asked Questions
Q1. What problem does the React Context API solve?
It solves prop drilling โ the need to pass props through many intermediate components
that don't actually use that data themselves.
Q2. Is Context API a replacement for Redux?
For small to medium apps, Context API can replace simple global state needs. For large apps
with complex, frequently-changing state, a dedicated state management library is often still preferred.
Q3. Can a component both provide and consume context?
Yes. A component can read a context value with useContext and also update it
(for example, via a state setter passed in the context value), as shown in the ThemedButton example.
Features and Learnings:-
createContext().Provider component.useContext hook.