Introduction

provides a way to pass data through the component tree without having to pass props down manually at every level.

Context is designed to share data that can be considered "global" for a tree of React components, such as the current authenticated user, theme, or preferred language.

Use a Provider to pass the current theme to the tree below. Any component can read it, no matter how deep it is.


    const ThemeContext = React.createContext('light');

    class App extends React.Component {
        render() {
            return ( <ThemeContext.Provider value="dark"> <Toolbar /> </ThemeContext.Provider> );
        }
    }

    // A component in the middle doesn't have to pass the theme down explicitly anymore.
    function Toolbar() {
        return ( <div> <ThemedButton /> </div> );
    }

    class ThemedButton extends React.Component {
        // Assign a contextType to read the current theme context.
        // React will find the closest theme Provider above and use its value.
        static contextType = ThemeContext;
        render() { return <Button theme={this.context} />; }
    }
        
// If you only want to avoid passing some props through many levels, component composition is often a simpler solution than context.
// Alternatively, instead of passing down the props 9 levels to be used only by the component in the 10th level, we can create the 10th level element in the 1st level and pass it down to 10th level. Here, the mid-9 components need not worry about the props. But having such complexity in the higher level may make the app more complex as it may contain multiple children

API

React.createContext

Creates a Context object. When React renders a component that subscribes to this Context object it will read the current context value from the closest matching Provider above it in the tree.

The defaultValue argument is only used when a component does not have a matching Provider above it in the tree.


    const MyContext = React.createContext(defaultValue);
        

Context.Provider

Every Context object comes with a Provider React component that allows consuming components to subscribe to context changes

The Provider component accepts a value prop to be passed to consuming components that are descendants of this Provider. One Provider can be connected to many consumers. Providers can be nested to override values deeper within the tree.

All consumers that are descendants of a Provider will re-render whenever the Provider’s value prop changes.


    <MyContext.Provider value={/* some value */}>
        

Class.contextType

The contextType property on a class can be assigned a Context object created by React.createContext(). Using this property lets you consume the nearest current value of that Context type using this.context


    class MyClass extends React.Component {
        static contextType = MyContext; // either this way
        componentDidMount() { let value = this.context; }
        componentDidUpdate() { let value = this.context; }
        componentWillUnmount() { let value = this.context; }
        render() { let value = this.context; }
    }
    MyClass.contextType = MyContext; // or this way
        
// You can only subscribe to a single context using this API.

Context.Consumer

A React component that subscribes to context changes. Using this component lets you subscribe to a context within a function component.

Requires a function as a child. The function receives the current context value and returns a React node. The value argument passed to the function will be equal to the value prop of the closest Provider for this context above in the tree. If there is no Provider for this context above, the value argument will be equal to the defaultValue that was passed to createContext().


    <MyContext.Consumer> {value => /* render something based on the context value */} </MyContext.Consumer>
        

Context.displayName

Context object accepts a displayName string property. React DevTools uses this string to determine what to display for the context.


    const MyContext = React.createContext(/* some value */);
    MyContext.displayName = 'MyDisplayName';

    <MyContext.Provider> // "MyDisplayName.Provider" in DevTools
    <MyContext.Consumer> // "MyDisplayName.Consumer" in DevTools
        

Examples

Dynamic Context


    /* theme-context.js */
    export const themes = {
      light: { foreground: '#000000', background: '#eeeeee' },
      dark: { foreground: '#ffffff', background: '#222222' }
    };

    export const ThemeContext = React.createContext( themes.dark ); // default value

    /* themed-button.js */
    import {ThemeContext} from './theme-context';

    class ThemedButton extends React.Component {
      render() {
        let props = this.props; let theme = this.context;
        return ( <button {...props} style={{backgroundColor: theme.background}} /> );
      }
    }

    ThemedButton.contextType = ThemeContext;

    /* app.js */
    import {ThemeContext, themes} from './theme-context';
    import ThemedButton from './themed-button';

    // An intermediate component that uses the ThemedButton
    function Toolbar(props) {
      return ( <ThemedButton onClick={props.changeTheme}> Change Theme </ThemedButton> );
    }

    class App extends React.Component {
      constructor(props) {
        super(props);
        this.state = { theme: themes.light, };

        this.toggleTheme = () => {
          this.setState(state => ({ theme: state.theme === themes.dark ? themes.light : themes.dark, }));
        };
      }

      // The ThemedButton button inside the ThemeProvider uses the theme from state while the one outside uses the default dark theme
      render() {
        return (
          <Page>
            <ThemeContext.Provider value={this.state.theme}> <Toolbar changeTheme={this.toggleTheme} /> </ThemeContext.Provider>
            <Section> <ThemedButton /> </Section>
          </Page>
        );
      }
    }

    ReactDOM.render(<App />, document.root);
      

Updating Context from a Nested Component


    /* theme-context.js */
    // Make sure the shape of the default value passed to createContext matches the shape that the consumers expect!
    export const ThemeContext = React.createContext({ theme: themes.dark, toggleTheme: () => {} });

    /* theme-toggler-button.js */
    import {ThemeContext} from './theme-context';

    function ThemeTogglerButton() {
        return (
            <ThemeContext.Consumer>
                {({theme, toggleTheme}) => ( <button onClick={toggleTheme} style={{backgroundColor: theme.background}}> Toggle Theme </button> )}
            </ThemeContext.Consumer>
        );
    }

    export default ThemeTogglerButton;

    /* app.js */
    import {ThemeContext, themes} from './theme-context';
    import ThemeTogglerButton from './theme-toggler-button';

    class App extends React.Component {
        constructor(props) {
            super(props);
            this.toggleTheme = () => { this.setState(state => ({ theme: state.theme === themes.dark ? themes.light : themes.dark })); };
            // State also contains the updater function so it will be passed down into the context provider
            this.state = { theme: themes.light, toggleTheme: this.toggleTheme, };
        }

        render() { // The entire state is passed to the provider
            return ( <ThemeContext.Provider value={this.state}> <Content /> </ThemeContext.Provider> );
        }
    }

    function Content() { return ( <div> <ThemeTogglerButton /> </div> ); }

    ReactDOM.render(<App />, document.root);
        

Multiple Contexts


    const ThemeContext = React.createContext('light');
    const UserContext = React.createContext({ name: 'Guest' });

    class App extends React.Component {
        render() {
            const {signedInUser, theme} = this.props;
            // App component that provides initial context values
            return ( <ThemeContext.Provider value={theme}> <UserContext.Provider value={signedInUser}> <Layout /> </UserContext.Provider> </ThemeContext.Provider> );
        }
    }

    function Layout() {
        return ( <div> <Sidebar /> <Content /> </div> );
    }

    function Content() {
        return (
            <ThemeContext.Consumer>
            { theme => (
                <UserContext.Consumer> { user => ( <ProfilePage user={user} theme={theme} /> )} </UserContext.Consumer>
            )}
            </ThemeContext.Consumer>
        );
    }
        

Caveats

Because context uses reference identity to determine when to re-render, there are some gotchas that could trigger unintentional renders in consumers when a provider’s parent re-renders.

instead of


    class App extends React.Component {
        render() {
            return ( <MyContext.Provider value={{something: 'something'}}> <Toolbar /> </MyContext.Provider> );
        }
    }
        

do


    class App extends React.Component {
        constructor(props) {
            super(props); this.state = { value: {something: 'something'} };
        }

        render() {
            return ( <MyContext.Provider value={this.state.value}> <Toolbar /> </MyContext.Provider> );
        }
    }