Learn

The previous exercise had you set up a wrapper component around a Context .Provider component. Now we’re going to make use of that wrapper component by working with React state.

Many React applications use prop drilling to pass down two values: a piece of state and the state updater function to update that state. Child components may then use the state updater function to change the state of their ancestors. For example:

const CounterApp = () => { const [count, setCount] = useState(0); return ( <Counter count={count} setCount={setCount} /> ); };

In this example, Counter can use the setCount() function to update the count value of CounterApp.

React Contexts can also be used to provide state and state updater functions. One common pattern is to have the context provide an object containing both of those values. Child components that consume the context can then use both (or either of) the state and the state updater function.

In this example, CounterArea provides the count value and the setCount() function to its descendants using context. The Counter component extracts both values from the provided context.

const CounterContext = React.createContext(); const CounterArea = ({ children }) => { const [count, setCount] = useState(0); return ( <CounterContext.Provider value={{ count, setCount }}> {children} </CounterContext.Provider> ); }; const Counter = () => { const { count, setCount } = useContext(CounterContext); return ( <button onClick={() => setCount(count => count+1)}> {count} </button> ); }; const CounterApp = () => { return ( <CounterArea> <Counter /> </CounterArea> ) }

In this exercise, you’ll add logic to the ThemeArea component that sets up a piece of state and a state updater function for its context. In doing so, you’ll allow the ThemeContext to have its theme updated by child components.

Instructions

1.

Many React Contexts are made to store an object with multiple properties, rather than a single string value the way ThemeContext does now. For this application, we’d like to share a state value and a state setter function to all consumers of ThemeContext.

First, in the ThemeArea component, call useState() to create a piece of state named theme along with a state setter function. Use the initialTheme prop as the initial state value.

2.

Now that we have multiple values to pass to consumers of ThemeContext, we need to modify the value of the ThemeContext.Provider component’svalue prop.

  • Provide an object containing both the theme and setTheme values to the ThemeContext.Provider component with the value prop.
  • Then, in ContactItem.js, use destructuring to access only the theme value from the object returned by useContext().

We only need theme for this component. We’ll use setTheme soon!

3.

Great, now all children of ThemeArea have access to both the theme state and its setTheme updater function. Let’s make a component that renders a button users can click to switch the theme between "dark" and "light".

Create a new file in the editor named ThemeSwitcher.js. Then:

  • Create and export a ThemeSwitcher component in that file.
  • ThemeSwitcher should retrieve both setTheme and theme from ThemeContext as variables.
  • It should also render a button whose text content is Theme is currently: {theme}.
4.

So far the ThemeSwitcher component only displays the current theme. Let’s add it to the application to make sure it does that correctly before we add more features.

Import the ThemeSwitcher component into ContactsSection.js. Render it as a child of the ContactsSection component, immediately after the h2.

5.

At this point there should be buttons on the screen that display what theme their contacts section is rendering with. The buttons don’t do anything when clicked – yet!

In the ThemeSwitcher component, add an onClick callback on the <button>. It should call setTheme with "dark" if the current theme is "light", or "light" if the current theme is "dark".

Sign up to start coding

Mini Info Outline Icon
By signing up for Codecademy, you agree to Codecademy's Terms of Service & Privacy Policy.

Or sign up using:

Already have an account?