Prop Drilling and Context API: Simplifying React State Sharing
Learn to stop prop drilling in your React applications. Discover how the Context API lets you share data globally without manual prop passing.
Previously in this course, we explored extracting custom hooks to clean up our component logic. While hooks handle logic reuse beautifully, we often run into a structural issue: passing data through layers of components that don't actually need it.
In our movie-browser app, imagine we want to support a "Dark Mode" theme or user authentication status. If we keep passing these values as props from the top-level App component down through every intermediate component just to reach a MovieCard deep in the tree, we are suffering from prop drilling.
What is Prop Drilling?
Prop drilling occurs when you pass data through components that don't use that data, simply to move it to a grandchild or great-grandchild component. It makes your code fragile; if you decide to change the component structure, you have to refactor every middle-man component in the chain.
The Context API is React's built-in solution for this. It acts as a "pipe" that bypasses the intermediate layers, allowing you to inject data directly into any component that needs it.
Creating and Using a Context
To use the Context API, you follow a three-step pattern:
- Create the Context: Define the container for your data.
- Provide the Context: Wrap your component tree with a Provider.
- Consume the Context: Access the data using the
useContexthook.
Step 1: Create the Context
We usually define this in a separate file to keep our project organized. Let’s create a ThemeContext.js.
JAVASCRIPT// src/context/ThemeContext.js import { createContext } from CE9178">'react'; // We provide a default value(e.g., CE9178">'light') export const ThemeContext = createContext(CE9178">'light');
Step 2: Provide the Data
In your App.jsx, you wrap the components that need access to this data with the Provider component.
JAVASCRIPT// src/App.jsx import { ThemeContext } from CE9178">'./context/ThemeContext'; function App() { return ( <ThemeContext.Provider value="dark"> <MainLayout /> </ThemeContext.Provider> ); }
Step 3: Consume the Data
Inside any child component, you import the useContext hook and the context object you created.
JAVASCRIPT// src/components/MovieCard.jsx import { useContext } from CE9178">'react'; import { ThemeContext } from CE9178">'../context/ThemeContext'; function MovieCard({ title }) { const theme = useContext(ThemeContext); return ( <div className={CE9178">`card ${theme}`}> <h3>{title}</h3> </div> ); }
Hands-on Exercise: Implementing a User Context
In your movie-browser project, create a UserContext to store a username.
- Create a
UserContext.jsfile. - Wrap your
Appcomponent withUserContext.Providerand pass a string value. - Consume this username in your
Headercomponent to display "Welcome, [username]". - Verify that you didn't have to pass the username as a prop to any components between
AppandHeader.
Common Pitfalls
- Overusing Context: Don't use Context for everything. If a piece of data only needs to be used by a parent and its immediate child, just use props. Context is for global or deeply shared data.
- Performance Issues: Every time the value passed to the
Providerchanges, every component consuming that context will re-render. Keep your context values stable. - Forgetting the Provider: If you try to
useContextoutside of aProvider, React will return the default value you set increateContext. This can lead to silent bugs where your UI doesn't reflect the expected state.
For more advanced patterns on managing state without bloat, see the React Context API Guide: Solving State Management Without Bloat. If you find yourself needing complex dependency injection for larger apps, you might eventually look into TypeScript React Dependency Injection: Stop Prop Drilling Now.
By leveraging the Context API, you keep your component interfaces clean and your data flow predictable. You've now moved beyond simple prop passing into architecture-level state management.
Up next: We will begin Polishing the UI by adding transitions and refining our layout to make the movie browser feel like a production-ready application.
Work with me

Headless WordPress + Next.js Frontend Development
Keep WordPress for content, get a lightning-fast Next.js frontend. The best of both worlds — familiar editing, modern speed.

Next.js Full-Stack Web App Development
A fast, SEO-ready full-stack web app built with Next.js 16 — from idea to deployed product, by an engineer who ships to production.