Codecademy Logo

Advanced React: Context

Context Wrappers

Some React applications use a dedicated “wrapper” component around a Context Provider to set up state for the Context. Doing so can help standardize setting up state for each usage of the Provider.

const ThemeContext = React.createContext();
// Wrapper for ThemeContext that adds a friendly notice
const ThemedMessage = ({ children, theme }) => {
return (
<ThemeContext.Provider value={theme}>
<p>This content is in {theme} mode!</p>
{children}
</ThemeContext.Provider>
);
};

Context Providers

React Context objects include a .Provider property that is a React component. It takes in a value prop to be made available to all its descendent components.

// Provides "hello world" as the MyContext value to descendants
<MyContext.Provider value="hello world">
<ChildComponent />
</MyContext.Provider>

Using Context Values

Descendents of a Context Provider may subscribe to the Provider’s data by passing the Context object to React’s useContext() hook.

import MyContext from 'MyContext.js';
const ConsumerComponent = () => {
const contextValue = useContext(MyContext);
// The component can then use contextValue
}

Creating Contexts

The React.createContext() function creates and returns a React Context object.

const CounterContext = React.createContext();

Dynamic Context Values

A Context’s .Provider component may provide both a state value and its updater function via the value prop.

const CounterContext = React.createContext();
// Descendants of CounterArea will be able to update its count state by calling the `setCount` property provided by the CounterContext.Provider
const CounterArea = ({ children }) => {
const [count, setCount] = useState(0);
return (
<CounterContext.Provider value={{ count, setCount }}>
{children}
</CounterContext.Provider>
);
};

Context

Context is a feature of React that allows us to create a piece of state that any component within an area of your application can subscribe to.

Prop Drilling

Prop drilling is the term for when a piece of data is passed as a prop through a large number of components in a React application.

const App = () => {
const [count, setCount] = useState(0);
return <CounterContainer count={count} setCount={setCount} />
}
// This component drills props down to CounterDisplay and CounterButton
const CounterContainer = ({count, setCount}) => {
return (
<>
<CounterDisplay count={count}/>
<CounterButton setCount={setCount}/>
</>
)
}
const CounterDisplay = ({count}) => {
return <h2>{count}</h2>
}
const CounterButton = ({setCount}) => {
return <button setCount={setCount}>Increment</button>
}

Downsides of Prop Drilling

Downsides of prop drilling include components being harder to understand and excess rerenders of components that pass props without using them.

// This component prop drills three props: apple, banana, and cherry
const MyComponent = ({ apple, banana, cherry, children }) => {
return (
<ChildComponent apple={apple} banana={banana} cherry={cherry}>
{children}
</ChildComponent>
);
};

Multiple Providers

A .Provider component can be used in multiple places in your application to provide different values for that subtree.

// The theme for App, Header, and Body will be "light". Only Footer will have the "dark" theme.
<ThemeContext.Provider value="light">
<App>
<Header />
<Body />
<ThemeContext.Provider value="dark">
<Footer />
</ThemeContext.Provider>
</App>
</ThemeContext.Provider>

Learn more on Codecademy