--- title: useContext --- `useContext` is a React Hook that lets you read and subscribe to [context](/learn/passing-data-deeply-with-context) from your component. ```js const value = useContext(SomeContext) ``` --- ## Usage {/*usage*/} ### Passing data deeply into the tree {/*passing-data-deeply-into-the-tree*/} Call `useContext` at the top level of your component to read and subscribe to [context.](/learn/passing-data-deeply-with-context) ```js [[2, 4, "theme"], [1, 4, "ThemeContext"]] import { useContext } from 'react'; function Button() { const theme = useContext(ThemeContext); // ... ``` `useContext` returns the context value for the context you passed. To determine the context value, React searches the component tree and finds **the closest context provider above** for that particular context. To pass context to a `Button`, wrap it or one of its parent components into the corresponding context provider: ```js [[1, 3, "ThemeContext"], [2, 3, "\"dark\""], [1, 5, "ThemeContext"]] function MyPage() { return (
); } function Form() { // ... renders buttons inside ... } ``` It doesn't matter how many layers of components there are between the provider and the `Button`. When a `Button` *anywhere* inside of `Form` calls `useContext(ThemeContext)`, it will receive `"dark"` as the value. `useContext()` always looks for the closest provider *above* the component that calls it. It searches upwards and **does not** consider providers in the component from which you're calling `useContext()`. ```js import { createContext, useContext } from 'react'; const ThemeContext = createContext(null); export default function MyApp() { return ( ) } function Form() { return ( ); } function Panel({ title, children }) { const theme = useContext(ThemeContext); const className = 'panel-' + theme; return (

{title}

{children}
) } function Button({ children }) { const theme = useContext(ThemeContext); const className = 'button-' + theme; return ( ); } ``` ```css .panel-light, .panel-dark { border: 1px solid black; border-radius: 4px; padding: 20px; } .panel-light { color: #222; background: #fff; } .panel-dark { color: #fff; background: rgb(23, 32, 42); } .button-light, .button-dark { border: 1px solid #777; padding: 5px; margin-right: 10px; margin-top: 10px; } .button-dark { background: #222; color: #fff; } .button-light { background: #fff; color: #222; } ```
--- ### Updating data passed via context {/*updating-data-passed-via-context*/} Often, you'll want the context to change over time. To update context, you need to combine it with [state.](/apis/react/useState) Declare a state variable in the parent component, and pass the current state down as the context value to the provider. ```js {2} [[1, 4, "ThemeContext"], [2, 4, "theme"], [1, 11, "ThemeContext"]] function MyPage() { const [theme, setTheme] = useState('dark'); return ( ); } ``` Now any `Button` inside of the provider will receive the current `theme` value. If you call `setTheme` to update the `theme` value that you pass to the provider, all `Button` components will re-render with the new `'light'` value. #### Updating a value via context {/*updating-a-value-via-context*/} In this example, the `MyApp` component holds a state variable which is then passed to the `ThemeContext` provider. Checking the "Dark mode" checkbox updates the state. Changing the provided value re-renders all the components using that context. ```js import { createContext, useContext, useState } from 'react'; const ThemeContext = createContext(null); export default function MyApp() { const [theme, setTheme] = useState('light'); return ( ) } function Form({ children }) { return ( ); } function Panel({ title, children }) { const theme = useContext(ThemeContext); const className = 'panel-' + theme; return (

{title}

{children}
) } function Button({ children }) { const theme = useContext(ThemeContext); const className = 'button-' + theme; return ( ); } ``` ```css .panel-light, .panel-dark { border: 1px solid black; border-radius: 4px; padding: 20px; margin-bottom: 10px; } .panel-light { color: #222; background: #fff; } .panel-dark { color: #fff; background: rgb(23, 32, 42); } .button-light, .button-dark { border: 1px solid #777; padding: 5px; margin-right: 10px; margin-top: 10px; } .button-dark { background: #222; color: #fff; } .button-light { background: #fff; color: #222; } ```
Note that `value="dark"` passes the `"dark"` string, but `value={theme}` passes the value of the JavaScript `theme` variable with [JSX curly braces.](/learn/javascript-in-jsx-with-curly-braces) Curly braces also let you pass context values that aren't strings. #### Updating an object via context {/*updating-an-object-via-context*/} In this example, there is a `currentUser` state variable which holds an object. You combine `{ currentUser, setCurrentUser }` into a single object and pass it down through the context inside the `value={}`. This lets any component below, such as `LoginButton`, read both `currentUser` and `setCurrentUser`, and then call `setCurrentUser` when needed. ```js import { createContext, useContext, useState } from 'react'; const CurrentUserContext = createContext(null); export default function MyApp() { const [currentUser, setCurrentUser] = useState(null); return ( ); } function Form({ children }) { return ( ); } function LoginButton() { const { currentUser, setCurrentUser } = useContext(CurrentUserContext); if (currentUser !== null) { return

You logged in as {currentUser.name}.

; } return ( ); } function Panel({ title, children }) { return (

{title}

{children}
) } function Button({ children, onClick }) { return ( ); } ``` ```css label { display: block; } .panel { border: 1px solid black; border-radius: 4px; padding: 20px; margin-bottom: 10px; } .button { border: 1px solid #777; padding: 5px; margin-right: 10px; margin-top: 10px; } ```
#### Multiple contexts {/*multiple-contexts*/} In this example, there are two independent contexts. `ThemeContext` provides the current theme, which is a string, while `CurrentUserContext` holds the object representing the current user. ```js import { createContext, useContext, useState } from 'react'; const ThemeContext = createContext(null); const CurrentUserContext = createContext(null); export default function MyApp() { const [theme, setTheme] = useState('light'); const [currentUser, setCurrentUser] = useState(null); return ( ) } function WelcomePanel({ children }) { const {currentUser} = useContext(CurrentUserContext); return ( {currentUser !== null ? : } ); } function Greeting() { const {currentUser} = useContext(CurrentUserContext); return (

You logged in as {currentUser.name}.

) } function LoginForm() { const {setCurrentUser} = useContext(CurrentUserContext); const [firstName, setFirstName] = useState(''); const [lastName, setLastName] = useState(''); const canLogin = firstName !== '' && lastName !== ''; return ( <> {!canLogin && Fill in both fields.} ); } function Panel({ title, children }) { const theme = useContext(ThemeContext); const className = 'panel-' + theme; return (

{title}

{children}
) } function Button({ children, disabled, onClick }) { const theme = useContext(ThemeContext); const className = 'button-' + theme; return ( ); } ``` ```css label { display: block; } .panel-light, .panel-dark { border: 1px solid black; border-radius: 4px; padding: 20px; margin-bottom: 10px; } .panel-light { color: #222; background: #fff; } .panel-dark { color: #fff; background: rgb(23, 32, 42); } .button-light, .button-dark { border: 1px solid #777; padding: 5px; margin-right: 10px; margin-top: 10px; } .button-dark { background: #222; color: #fff; } .button-light { background: #fff; color: #222; } ```
#### Extracting providers to a component {/*extracting-providers-to-a-component*/} As your app grows, it is expected that you'll have a "pyramid" of contexts closer to the root of your app. There is nothing wrong with that. However, if you dislike the nesting aesthetically, you can extract the providers into a single component. In this example, `MyProviders` hides the "plumbing" and renders the children passed to it inside the necessary providers. Note that the `theme` and `setTheme` state is needed in `MyApp` itself, so `MyApp` still owns that piece of the state. ```js import { createContext, useContext, useState } from 'react'; const ThemeContext = createContext(null); const CurrentUserContext = createContext(null); export default function MyApp() { const [theme, setTheme] = useState('light'); return ( ); } function MyProviders({ children, theme, setTheme }) { const [currentUser, setCurrentUser] = useState(null); return ( {children} ); } function WelcomePanel({ children }) { const {currentUser} = useContext(CurrentUserContext); return ( {currentUser !== null ? : } ); } function Greeting() { const {currentUser} = useContext(CurrentUserContext); return (

You logged in as {currentUser.name}.

) } function LoginForm() { const {setCurrentUser} = useContext(CurrentUserContext); const [firstName, setFirstName] = useState(''); const [lastName, setLastName] = useState(''); const canLogin = firstName !== '' && lastName !== ''; return ( <> {!canLogin && Fill in both fields.} ); } function Panel({ title, children }) { const theme = useContext(ThemeContext); const className = 'panel-' + theme; return (

{title}

{children}
) } function Button({ children, disabled, onClick }) { const theme = useContext(ThemeContext); const className = 'button-' + theme; return ( ); } ``` ```css label { display: block; } .panel-light, .panel-dark { border: 1px solid black; border-radius: 4px; padding: 20px; margin-bottom: 10px; } .panel-light { color: #222; background: #fff; } .panel-dark { color: #fff; background: rgb(23, 32, 42); } .button-light, .button-dark { border: 1px solid #777; padding: 5px; margin-right: 10px; margin-top: 10px; } .button-dark { background: #222; color: #fff; } .button-light { background: #fff; color: #222; } ```
#### Scaling up with context and a reducer {/*scaling-up-with-context-and-a-reducer*/} In larger apps, it is common to combine context with a [reducer](/apis/react/useReducer) to extract the logic related to some state out of components. In this example, all the "wiring" is hidden in the `TasksContext.js`, which contains a reducer and two separate contexts. Read a [full walkthrough](/learn/scaling-up-with-reducer-and-context) of this example. ```js App.js import AddTask from './AddTask.js'; import TaskList from './TaskList.js'; import { TasksProvider } from './TasksContext.js'; export default function TaskApp() { return (

Day off in Kyoto

); } ``` ```js TasksContext.js import { createContext, useContext, useReducer } from 'react'; const TasksContext = createContext(null); const TasksDispatchContext = createContext(null); export function TasksProvider({ children }) { const [tasks, dispatch] = useReducer( tasksReducer, initialTasks ); return ( {children} ); } export function useTasks() { return useContext(TasksContext); } export function useTasksDispatch() { return useContext(TasksDispatchContext); } function tasksReducer(tasks, action) { switch (action.type) { case 'added': { return [...tasks, { id: action.id, text: action.text, done: false }]; } case 'changed': { return tasks.map(t => { if (t.id === action.task.id) { return action.task; } else { return t; } }); } case 'deleted': { return tasks.filter(t => t.id !== action.id); } default: { throw Error('Unknown action: ' + action.type); } } } const initialTasks = [ { id: 0, text: 'Philosopher’s Path', done: true }, { id: 1, text: 'Visit the temple', done: false }, { id: 2, text: 'Drink matcha', done: false } ]; ``` ```js AddTask.js import { useState, useContext } from 'react'; import { useTasksDispatch } from './TasksContext.js'; export default function AddTask({ onAddTask }) { const [text, setText] = useState(''); const dispatch = useTasksDispatch(); return ( <> setText(e.target.value)} /> ); } let nextId = 3; ``` ```js TaskList.js import { useState, useContext } from 'react'; import { useTasks, useTasksDispatch } from './TasksContext.js'; export default function TaskList() { const tasks = useTasks(); return (
    {tasks.map(task => (
  • ))}
); } function Task({ task }) { const [isEditing, setIsEditing] = useState(false); const dispatch = useTasksDispatch(); let taskContent; if (isEditing) { taskContent = ( <> { dispatch({ type: 'changed', task: { ...task, text: e.target.value } }); }} /> ); } else { taskContent = ( <> {task.text} ); } return ( ); } ``` ```css button { margin: 5px; } li { list-style-type: none; } ul, li { margin: 0; padding: 0; } ```
--- ### Specifying a fallback default value {/*specifying-a-fallback-default-value*/} If React can't find any providers of that particular context in the parent tree, the context value returned by `useContext()` will be equal to the default value that you specified when you [created that context](/apis/react/createContext): ```js [[1, 1, "ThemeContext"], [3, 1, "null"]] const ThemeContext = createContext(null); ``` The default value **never changes**. If you want to update context, use it with state as [described above.](#updating-data-passed-via-context) Often, instead of `null`, there is some more meaningful value you can use as a default, for example: ```js [[1, 1, "ThemeContext"], [3, 1, "light"]] const ThemeContext = createContext('light'); ``` This way, if you accidentally render some component without a corresponding provider, it won't break. This also helps your components work well in a test environment without setting up a lot of providers in the tests. In the example below, the "Toggle theme" button is always light because it's **outside any theme context provider** and the default context theme value is `'light'`. Try editing the default theme to be `'dark'`. ```js import { createContext, useContext, useState } from 'react'; const ThemeContext = createContext('light'); export default function MyApp() { const [theme, setTheme] = useState('light'); return ( <> ) } function Form({ children }) { return ( ); } function Panel({ title, children }) { const theme = useContext(ThemeContext); const className = 'panel-' + theme; return (

{title}

{children}
) } function Button({ children, onClick }) { const theme = useContext(ThemeContext); const className = 'button-' + theme; return ( ); } ``` ```css .panel-light, .panel-dark { border: 1px solid black; border-radius: 4px; padding: 20px; margin-bottom: 10px; } .panel-light { color: #222; background: #fff; } .panel-dark { color: #fff; background: rgb(23, 32, 42); } .button-light, .button-dark { border: 1px solid #777; padding: 5px; margin-right: 10px; margin-top: 10px; } .button-dark { background: #222; color: #fff; } .button-light { background: #fff; color: #222; } ```
--- ### Overriding context for a part of the tree {/*overriding-context-for-a-part-of-the-tree*/} You can override the context for a part of the tree by wrapping that part in a provider with a different value. ```js {3,5} ...