Lesson 10. Using contexts to share values between components 2. Updating a context value
Our theme context is nice, but it only returns static values. What if we want to update some of the context’s values? Here we will improve our context to handle two themes: a light one and a dark one. What we want is to offer the possibility of switching between the light and the dark theme.
If you look at our ThemeProvider, you’ll notice that it’s actually just a
React component: instead of using a static theme, nothing prevents us from using
a local state to store a theme that can be updated.
We will keep two variables for the different themes, and a local state will
contain one of the two variables. By declaring a toggle function and putting
it into the context value, we can provide the ability to switch from one theme
to the other:
const lightTheme = { background: 'white', foreground: 'black' }const darkTheme = { background: 'black', foreground: 'white' }const ThemeProvider = ({ children, initialTheme = lightTheme }) => {const [theme, setTheme] = useState(initialTheme)const toggle = () => {setTheme(theme === lightTheme ? darkTheme : lightTheme)}return (<themeContext.Provider value={{ theme, toggle }}>{children}</themeContext.Provider>)}
Our context value contains two attributes: one for the theme and one for the
function toggle.
To access this toggle function in consumer components, of course we could use
the same hook useTheme, which could return both the theme and the update
function. But since custom hooks provide us a way to create small hooks
dedicated to a specific task, let’s create a new hook specifically to get this
toggle function:
const useToggleTheme = () => {const { toggle } = useContext(themeContext)return toggle}
We can now create a ThemeToggler component using this hook, and insert it
wherever we want in the component hierarchy:
const ThemeToggler = () => {const toggle = useToggleTheme()return <button onClick={() => toggle()}>Toggle</button>}const App = () => {return (<ThemeProvider><Label>Hello</Label><ThemeToggler /></ThemeProvider>)}
Here is the final code with all the puzzle’s pieces:
Result
Note that for a component to use a context, it doesn’t have to be a direct child of the provider. You can use it very deep in the components hierarchy, and this is the advantage of the contexts compared to props passed from parent to children components.