[REACT](https://www.kirupa.com/react/index.htm) [BOOK](https://www.amazon.com/exec/obidos/ASIN/0134546318/kirupacom) # Sharing Data with Context by [ kirupa](https://www.kirupa.com/me/index.htm) | filed under [Learning React](https://www.kirupa.com/react/index.htm) In React, data flows down from parent to child through props. That is great when the child that needs the data is right below the parent. It's less great when the component that needs the data is five levels down, and every component in between has to carry it along like a relay runner who doesn't care about the baton. React has a built-in answer to this called **context**. It lets a component make some data available to everything below it in the tree, and any component down there can grab the data directly. In this tutorial, we'll look at the problem context solves, how to use it, and (just as important) when not to use it. Onwards! ## The Problem: Prop Drilling Let's say we have an app with a logged-in user. The top of the app knows who the user is, and an avatar way down in the sidebar wants to say hello to them. Here is what that looks like with props: ```jsx function App() { const user = { name: "Bruce Wayne" }; return ; } function Page({ user }) { return ; } function Sidebar({ user }) { return ; } function Avatar({ user }) { return

Hi, {user.name}

; } ``` Take a look at `Page` and `Sidebar`. Neither of them cares about the user. They only accept it so they can pass it along. This is known as **prop drilling**, and it has a few annoying side effects. Every component along the way needs to know about the prop. If you rename it or change its shape, you need to touch all of them. And it gets worse as you add more data that has to travel the same route. Before reaching for context, it's worth knowing that this isn't always a problem to solve. Passing props through two or three layers is perfectly normal, and it has one big benefit: you can see exactly where the data comes from. Context is for when the drilling really starts to hurt. ## Meet Context Context has three steps: create it, provide a value, and read the value. Let's go through them with something small first. We'll make a language setting that a component can read: ```jsx import { createContext, useContext } from "react"; const LanguageContext = createContext("en"); function Greeting() { const language = useContext(LanguageContext); return

{language === "en" ? "Hello" : "Bonjour"}

; } function App() { return ( ); } ``` If you run this, you will see "Bonjour". Let's look at what each step did. ### Step 1: Create the Context We create a context with `createContext`, and we pass it a **default value**: ```jsx const LanguageContext = createContext("en"); ``` The default value is what a component gets if it asks for the context and there is no provider above it. You create this once, outside of any component, usually in its own file so it can be imported wherever it is needed. ### Step 2: Provide a Value To make a value available to a part of your app, wrap that part of the tree with the context and give it a `value`: ```jsx ``` Every component inside, no matter how deeply nested, can now read `"fr"`. If you've seen older React code, you may remember that this used to be written as ``. That still works, but starting with React 19 you can use the context itself as the provider. The extra `.Provider` is no longer needed, and React has said it plans to deprecate it in a future version. ### Step 3: Read the Value Any component below the provider can call the `useContext` hook to get the value: ```jsx const language = useContext(LanguageContext); ``` React walks up the tree from that component until it finds the nearest `LanguageContext` provider, and hands back its value. If there is no provider, you get the default value we passed to `createContext`. The nearest provider wins, which means you can nest providers to override a value for just one part of the tree. React 19 also adds a function named `use` that can read context (`use(LanguageContext)`). It does the same job as `useContext`, with the extra ability to be called inside an `if` or a loop. For most code, `useContext` is all you need, and you will see it in the majority of codebases out there. Here is what this looks like in a bigger tree. The shared value in this picture is a theme, which we'll build in a moment: ![A component tree. A ThemeProvider sits at the top, with Page and Footer below it, then Sidebar and Content, then Avatar and ThemeToggle. Dotted pink arrows go straight from the provider to Avatar and ThemeToggle, skipping the components in between.](https://www.kirupa.com/react/images/context_provider_tree_144.png) The provider sits at the top. Avatar and ThemeToggle (the green boxes) ask for the value directly with `useContext`. Page, Sidebar, Content, and Footer don't need to know anything about it. No props, no drilling. ## A Provider That Holds State A fixed value like `"fr"` isn't very exciting. The real power shows up when the value comes from state, so that changing it updates every component that is reading it. A classic example is a light and dark theme. The usual approach is to create a small **provider component** that holds the state and wraps its children. We'll put it in its own file along with a custom hook to read the value: ```jsx import { createContext, useContext, useState } from "react"; const ThemeContext = createContext(null); export function ThemeProvider({ children }) { const [theme, setTheme] = useState("light"); function toggleTheme() { setTheme((current) => (current === "light" ? "dark" : "light")); } return ( {children} ); } export function useTheme() { const context = useContext(ThemeContext); if (context === null) { throw new Error("useTheme must be used inside a ThemeProvider"); } return context; } ``` There are a few things to unpack here. The context's value is an object with both the current `theme` and a `toggleTheme` function. This means components can read the theme and also change it. The default value is `null`, and `useTheme` checks for it. If you forget to wrap your app in a `ThemeProvider`, you get a clear error message right away instead of a mysterious crash when you try to read `theme` from `null`. The `useTheme` function is a custom hook, which is a function that uses other hooks. It's a nice way to hide the context from the rest of your code. Components don't need to import `ThemeContext` and `useContext`. They just call `useTheme()`. We'll look at custom hooks in more detail in the [next tutorial](https://www.kirupa.com/react/custom_hooks.htm). (One small note: some lint setups complain when a file exports both components and hooks. If yours does, move `useTheme` into its own file.) Now we can use it. Here is a card that reads the theme, with a button inside of it that changes it: ```jsx function ThemeToggle() { const { theme, toggleTheme } = useTheme(); return ( ); } function Card() { const { theme } = useTheme(); return (
); } function Footer() { return
Nothing to see here
; } function App() { return (