Codecademy Logo

Advanced React: Context

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>

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.

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 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> ); };

Multiple Providers

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

// 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>

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> ); };