Zettelkasten
week01
Exercise
Solution Based

#solution


Solution: Create a light-dark theme switcher

Here is the completed solution code for the ThemeContext.js file:

import { createContext, useContext, useState } from 'react';
 
const ThemeContext = createContext(undefined);
 
export const ThemeProvider = ({ children }) => {
  const [theme, setTheme] = useState('light');
 
  return (
    <ThemeContext.Provider
      value={{
        theme,
        toggleTheme: () => setTheme(theme === 'light' ? 'dark' : 'light'),
      }}
    >
            {children}
          
    </ThemeContext.Provider>
  );
};
 
export const useTheme = () => useContext(ThemeContext);

Here is the solution code for the Switch/index.js file:

import './Styles.css';
import { useTheme } from '../ThemeContext';
 
const Switch = () => {
  const { theme, toggleTheme } = useTheme();
 
  return (
    <label className="switch">
           
      <input type="checkbox" checked={theme === 'light'} onChange={toggleTheme} />
           
      <span className="slider round" />
         
    </label>
  );
};
 
export default Switch;

Steps

Step 1


To create the ThemeProvider, the first step is to create a new context object, ThemeContext, using createContext, a function that can be imported from React. The default value argument is only used when a component does not have a matching Provider above it in the tree. This default value can be helpful for testing components in isolation without wrapping them. For the purpose of this exercise, it’s not relevant, so undefined can be used.

Then, inside the ThemeProvider component, you need to define a new piece of local state for the theme, which can be a string whose value is either “light” or “dark”. It can be initialized to “light”, which is usually the default theme for applications.

In the return statement, the ThemeContext.Provider component should be rendered and wrap the children.

Finally, recall that the value prop for ThemeContext.Provider is what gets injected down the tree as context. Since the application needs both the theme value and a way to toggle it, two values are injected: theme and toggleTheme.

theme is just the light-dark theme string value, whereas toggleTheme is a function that receives no parameters and just toggles the theme from light to dark and vice versa.

That completes the implementation of the ThemeProvider component, as per the code below:

import { createContext, useContext, useState } from 'react';
 
const ThemeContext = createContext(undefined);
 
export const ThemeProvider = ({ children }) => {
  const [theme, setTheme] = useState('light');
 
  return (
    <ThemeContext.Provider
      value={{
        theme,
        toggleTheme: () => setTheme(theme === 'light' ? 'dark' : 'light'),
      }}
    >
           {children}
         
    </ThemeContext.Provider>
  );
};

Step 2


The implementation for useTheme is quite simple. You just need to import the useContext hook from React and pass as an argument the ThemeContext object defined before. That allows your components to access both theme and toggleTheme values, which are the ones the useTheme custom hook returns.

export const useTheme = () => useContext(ThemeContext);

export const useTheme = () => useContext(ThemeContext);

Step 3


The Switch component can then be connected to the toggleTheme function returned from useTheme as per the code below:

const Switch = () => {
  const { theme, toggleTheme } = useTheme();
  return (
    <label className="switch">
           
      <input type="checkbox" checked={theme === 'light'} onChange={toggleTheme} />
           
      <span className="slider round" />
         
    </label>
  );
};

Step 4


And, finally, you should be able to use the switch widget on the top right corner to change the theme of the application:

Introduction of little lemon page interface