Introduction to Context API in React – Detailed Notes
The React Context API is a React feature that allows components to share data with other components in the component tree without passing props manually through every intermediate component. It is useful for managing shared information such as themes, user details, language preferences, and shopping cart data.
React JS Training: JustAcademy React JS Training Course
Course Demo: Register for React JS Course Demo
1. What Is the Context API?
The Context API is a built-in React feature for sharing data across multiple components without explicitly passing that data through every level of the component hierarchy.
Normally, React components communicate by passing data from parent components to child components through props. However, when many components need the same information, passing props through several intermediate components can become inconvenient. Context provides an alternative for this situation.
Example
Suppose an application has the following component structure:
App
└── Dashboard
└── Profile
└── UserDetails
If the App component contains the user's name and UserDetails needs it, the value may have to pass through Dashboard and Profile even if those components do not use it. Context allows UserDetails to read the shared value directly from the nearest matching provider.
2. Why Do We Need the Context API?
The Context API is useful when the same information is required by multiple components located at different levels of the component tree.
- Reduce prop drilling: Avoid passing the same prop through multiple intermediate components.
- Share user information: Make the current user's details available to different sections of the application.
- Manage themes: Share light or dark mode preferences across components.
- Share language preferences: Make the selected language available to relevant components.
- Share application settings: Provide common configuration values to multiple components.
- Manage shared UI state: Share information such as cart contents or selected preferences.
3. What Is Prop Drilling?
Prop drilling occurs when a component passes props through intermediate components to reach a deeply nested component that actually needs the data.
Example Without Context API
function App() {
const username = "Rahul";
return <Dashboard username={username} />;
}
function Dashboard({ username }) {
return <Profile username={username} />;
}
function Profile({ username }) {
return <UserDetails username={username} />;
}
function UserDetails({ username }) {
return <h2>Welcome, {username}!</h2>;
}
export default App;
Explanation:
- The App component defines the username.
- Dashboard receives and passes the username.
- Profile receives and passes the same username.
- UserDetails finally displays the username.
Dashboard and Profile do not use the value themselves. They only forward it, making the code more difficult to maintain as the application grows.
How Context Helps
With Context API, App can provide the username, and UserDetails can read it directly using the useContext() Hook. The intermediate components no longer need to forward the username.
4. Important Functions Used in the Context API
| Function or Concept |
Purpose |
createContext() |
Creates a context object for sharing a value. |
useContext() |
Reads the value from the nearest matching context provider. |
| Context Provider |
Makes a value available to components below it. |
useState() |
Stores changeable state that can be supplied through context. |
useReducer() |
Manages more complex state transitions that can be shared through context. |
5. Step 1: Creating a Context with createContext()
The createContext() function creates a context object. It is normally called outside React components, often in a separate file so multiple components can import it.
Syntax
import { createContext } from "react";
const MyContext = createContext(defaultValue);
The defaultValue is used when a component reads the context and there is no matching provider above it in the component tree. It is a fallback value, not automatically changeable state.
Example: UserContext.js
import { createContext } from "react";
const UserContext = createContext("Guest");
export default UserContext;
In this example, the default context value is "Guest".
6. Step 2: Providing a Context Value
A context provider makes a value available to components within its subtree.
In React 19 and later, you can use the context object itself as a provider. In earlier React versions, use MyContext.Provider.
Example: Providing Context in App.jsx
import UserContext from "./UserContext";
import Profile from "./Profile";
function App() {
return (
<UserContext value="Rahul">
<Profile />
</UserContext>
);
}
export default App;
For React versions before React 19, use this provider syntax instead:
<UserContext.Provider value="Rahul">
<Profile />
</UserContext.Provider>
The value prop contains the data that components below the provider can read.
7. Step 3: Reading Context with useContext()
The useContext() Hook reads the current value of a context from the nearest matching provider above the component that calls it.
Syntax
const value = useContext(MyContext);
Example: Profile.jsx
import { useContext } from "react";
import UserContext from "./UserContext";
function Profile() {
const username = useContext(UserContext);
return <h2>Welcome, {username}!</h2>;
}
export default Profile;
Explanation:
useContext(UserContext) reads the current UserContext value.
- The provider supplies the value
"Rahul".
- The Profile component displays
Welcome, Rahul!.
8. Complete Example of Context API
This example demonstrates how to create a context, provide a value, and read it from a child component.
UserContext.js
import { createContext } from "react";
const UserContext = createContext("Guest");
export default UserContext;
App.jsx
import UserContext from "./UserContext";
import Profile from "./Profile";
function App() {
return (
<UserContext value="Amit">
<Profile />
</UserContext>
);
}
export default App;
Profile.jsx
import { useContext } from "react";
import UserContext from "./UserContext";
function Profile() {
const username = useContext(UserContext);
return (
<div>
<h1>User Profile</h1>
<p>Username: {username}</p>
</div>
);
}
export default Profile;
Expected Output:
User Profile
Username: Amit
Note: If you are using React 18 or earlier, replace with .
9. Using Context API with useState()
Context can share dynamic values as well as fixed values. By combining Context API with useState(), multiple components can read and update shared state.
Example: ThemeContext.js
import { createContext } from "react";
const ThemeContext = createContext(null);
export default ThemeContext;
App.jsx
import { useState } from "react";
import ThemeContext from "./ThemeContext";
import ThemeSwitcher from "./ThemeSwitcher";
function App() {
const [theme, setTheme] = useState("light");
const contextValue = { theme, setTheme };
return (
<ThemeContext value={contextValue}>
<div className={theme}>
<h1>Context API Theme Example</h1>
<ThemeSwitcher />
</div>
</ThemeContext>
);
}
export default App;
ThemeSwitcher.jsx
import { useContext } from "react";
import ThemeContext from "./ThemeContext";
function ThemeSwitcher() {
const { theme, setTheme } = useContext(ThemeContext);
const toggleTheme = () => {
setTheme(current =>
current === "light" ? "dark" : "light"
);
};
return (
<div>
<p>Current Theme: {theme}</p>
<button onClick={toggleTheme}>
Change Theme
</button>
</div>
);
}
export default ThemeSwitcher;
How it works:
- The App component stores the theme in state.
- The context provider shares the theme and its state setter.
- ThemeSwitcher reads both values through
useContext().
- Clicking the button updates the theme state.
- React re-renders components that use the changed context value.
Note: The example changes the theme value. To change the actual appearance of the page, add CSS rules for the light and dark classes.
10. Common Use Cases of Context API
| Use Case |
Example |
| Theme management |
Share light and dark mode preferences. |
| User information |
Make the current user's name available across components. |
| Authentication state |
Share the current user's status and relevant actions. |
| Language selection |
Share the selected language or locale. |
| Shopping cart |
Share cart items and cart-related actions. |
| Application settings |
Share preferences that multiple components need. |
| UI preferences |
Share display settings such as compact or expanded layout. |
11. Context API vs. Props
| Feature |
Props |
Context API |
| Data flow |
Passed from parent to child components. |
Provided to a subtree and read by descendant components. |
| Intermediate components |
May need to forward props. |
Do not need to forward the shared value unless they use it. |
| Best use |
Explicit component-specific data. |
Values needed by multiple descendants. |
| Setup |
Pass props directly. |
Create context, provide a value, and read it. |
| Scope |
Typically a direct component interface. |
The subtree covered by a matching provider. |
Best practice: Context does not replace props in every situation. Props are often clearer when data is needed by only one or two nearby components.
12. Context API vs. Redux
Context API and Redux can both help share application data, but they solve somewhat different needs.
| Feature |
Context API |
Redux |
| Availability |
Built into React. |
External state-management library. |
| Main purpose |
Make values available across a component subtree. |
Provide structured, centralized state management and predictable update patterns. |
| Setup |
Usually requires context creation and a provider. |
Typically uses a store, reducers, and a provider through Redux Toolkit. |
| Typical use |
Theme, locale, current user, shared UI state. |
Complex application state, workflows, and centralized updates. |
| Dev tools |
Basic debugging through React tools. |
Redux DevTools supports action and state inspection. |
Context API is often enough for straightforward shared state. Larger applications may benefit from Redux Toolkit or another state-management solution. Context itself does not automatically provide all the features of a dedicated state-management library.
13. Context API and Re-Rendering
When a provider receives a different value, React updates the components that read that context. This keeps the UI synchronized with shared state.
Important Points
- Components using the changed context value may re-render.
- A new object or function created on every render can cause unnecessary context updates.
- For complex context values,
useMemo() and useCallback() may help when profiling shows avoidable updates.
- Splitting unrelated values into separate contexts can make data dependencies clearer.
- Memoization is an optimization, not a requirement for every context.
14. Common Mistakes When Using Context API
- Forgetting the provider: Without a matching provider,
useContext() returns the context's default value.
- Using the wrong provider syntax: React 19 supports
; older versions use .
- Creating context inside a component: Define the context at module scope so the same context object can be imported consistently.
- Calling useContext conditionally: Call the Hook at the top level of the component or custom Hook.
- Using context for every prop: Prefer ordinary props when they make the component interface simpler and clearer.
- Passing an unsuitable default value: Choose a meaningful fallback or use
null when no default is appropriate, then handle that case.
- Putting all application state in one context: Separate unrelated data when doing so improves clarity and update behavior.
- Treating client-side context as secure storage: Context is not a security boundary. Sensitive authorization must be enforced by the backend.
15. Best Practices for Context API
- Create context objects outside React components.
- Use descriptive names such as
ThemeContext, UserContext, or CartContext.
- Keep provider components close to the part of the application that needs the shared value, unless it is truly app-wide.
- Use
useContext() to read context inside React components or custom Hooks.
- Combine context with
useState() or useReducer() when shared values need to change.
- Keep context values focused on related responsibilities.
- Use props for local, direct parent-to-child communication.
- Check the React version before choosing provider syntax.
- Consider performance only when there is a real need, and profile before optimizing.
- Never rely on context alone to protect sensitive data or secure application actions.
16. Context API with useReducer()
For more complex shared state, you can combine Context API with useReducer(). A reducer centralizes how state changes in response to actions, while context makes the state and dispatch function available to descendant components.
Example
import { createContext, useContext, useReducer } from "react";
const CounterContext = createContext(null);
function counterReducer(state, action) {
switch (action.type) {
case "increment":
return state + 1;
case "decrement":
return state - 1;
case "reset":
return 0;
default:
return state;
}
}
function CounterProvider({ children }) {
const [count, dispatch] = useReducer(counterReducer, 0);
return (
<CounterContext value={{ count, dispatch }}>
{children}
</CounterContext>
);
}
function CounterControls() {
const context = useContext(CounterContext);
if (context === null) {
throw new Error("CounterControls must be inside CounterProvider");
}
const { count, dispatch } = context;
return (
<div>
<p>Count: {count}</p>
<button onClick={() => dispatch({ type: "increment" })}>+</button>
<button onClick={() => dispatch({ type: "decrement" })}>-</button>
<button onClick={() => dispatch({ type: "reset" })}>Reset</button>
</div>
);
}
function App() {
return (
<CounterProvider>
<CounterControls />
</CounterProvider>
);
}
export default App;
Explanation: The reducer defines the available state transitions. CounterProvider shares the current count and dispatch function. CounterControls reads the context and dispatches actions when buttons are clicked.
17. Interview Questions and Answers
Q1. What is the Context API in React?
Answer: It is a built-in React feature that allows components to share values across a component subtree without passing props through every intermediate component.
Q2. What is prop drilling?
Answer: Prop drilling is the process of passing props through intermediate components to reach a deeply nested component that needs the data.
Q3. What does createContext() do?
Answer: It creates a context object that can be used to provide and read a shared value.
Q4. What does useContext() do?
Answer: It reads the current value from the nearest matching provider above the component.
Q5. What happens if a provider is missing?
Answer: React returns the default value supplied to createContext().
Q6. Can Context API store changing values?
Answer: Yes. Combine context with state or a reducer and pass the current value through the provider.
Q7. What is the difference between Context API and Redux?
Answer: Context makes values available to descendant components. Redux provides a dedicated state-management architecture with centralized updates and development tools.
Q8. Does Context API replace props?
Answer: No. Props remain useful for explicit communication between components, while context is helpful when many descendants need the same value.
Q9. Can a component use multiple contexts?
Answer: Yes. A component can call useContext() for multiple distinct contexts.
Q10. When should you avoid Context API?
Answer: Avoid using it for every piece of local state or when ordinary props provide a simpler and clearer solution.
18. Practice Exercises
- Create a UserContext and display the username in a deeply nested component.
- Create a ThemeContext that switches between light and dark mode.
- Build a LanguageContext that shares the selected language with multiple components.
- Create an authentication context that shares a current user and login status.
- Build a CartContext that shares cart item counts across a header and product page.
- Use Context API with
useReducer() to build a shared counter.
- Compare a prop-drilling example with an equivalent context-based implementation.
19. Quick Revision Checklist
- Understand what the Context API is.
- Understand prop drilling and why context can help.
- Know how to create context using
createContext().
- Know how to provide a value to descendant components.
- Understand how
useContext() reads a context value.
- Know how to share dynamic state using
useState().
- Understand how Context API can work with
useReducer().
- Know the differences between props, Context API, and Redux.
- Understand default values, provider scope, and re-rendering.
- Follow the Rules of Hooks and choose context only when appropriate.
20. Official Documentation and Learning Resources
21. React JS Training Resources
Learn React components, Hooks, state management, Context API, and practical application development through structured training and demonstrations.
Explore the Course: JustAcademy React JS Training Course
Register for a Demo: Register for React JS Course Demo
Conclusion
The React Context API provides a convenient way to share information across components without passing props through every intermediate level. By combining createContext(), a context provider, and useContext(), developers can share themes, user details, preferences, and other common values. For dynamic or complex state, context can be combined with useState() or useReducer(). Using it appropriately helps keep React applications organized and maintainable.