1

I'm actually a beginner in react so I just want to ask if I can use useReducer and useContext for themes like (dark mode & light mode), and redux for all other data state.

skyboyer
  • 22,209
  • 7
  • 57
  • 64
  • You can also manage that via using the redux state. Mange one state "isDarkMode" and handle all stuf. – Asif vora Sep 13 '21 at 04:58
  • A better option is work on one global state management store. Either use contextApi or use Redux for that. If you App is not very big, use ContextApi if not use Redux for that. – Umair Riaz Sep 13 '21 at 04:59
  • Well you can, but why would you? You will end up having two different global state – jean182 Sep 13 '21 at 04:59

1 Answers1

1

The useContext hook is the React hook equivalent of the Context. ... It takes a React context object as the argument and returns the current value from the context. useReducer is an alternative version of useState for more complex state changes.

Let's see how to implement it in React by using hooks and browser's localStorage. We will use here facebook's react-boilerplate. Clone it first by using the command npx create-react-app dark-mode, after cloning, change the root directory to dark-mode by using cd dark-mode and to run the application npm start, use this create-react-app for more details.

Let's add some darkness Create CSS Files

// light-theme.css

html[data-theme="light"]  {
  --color: rgb(5, 5, 5);
  --background-color: rgb(250, 250, 250);
}
// dark-theme.css

html[data-theme="dark"]  {
  --color: rgb(250, 250, 250);
  --background-color: rgb(5, 5, 5);
}

As of now, I have added only two color variables, later you can add as many color variables for your project. Don't hardcode color in any css files or in any inline styling, use only defined color variables.

// App.css

.App-header {
  background-color:var(--background-color);
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  font-size: calc(10px + 2vmin);
  color:var(--color);
}

I have used those color variables in App.css file.

Create DarkMode folder, add index.js and index.css files.

/ DarkMode/index.js

const DarkModeToggle = () => {
  const [isDark, setIsDark] = useState(localStorage.getItem("theme") === "dark" ? true : false);
  useEffect(() => {
    document
    .getElementsByTagName("HTML")[0]
    .setAttribute("data-theme", localStorage.getItem("theme"));
  },[]);

Using useState hook to store the current user theme preference, get the current user preference from localStorage. Suppose you are running the application for first time, you won't get the user theme preference in browser's localStorage, in that case false get set to the isDark hook and applied light theme to the application. I have used browser's localStorage to set the choosen user theme preference and update it while theme toggling. Set HTML data-theme attribute accordingly with current user theme preference.

Note: The data-* attribute is used to store custom data private to the page or application. The data-* attribute gives us the ability to embed custom data attributes on all HTML elements.

/ handles user theme preference change

const toggleThemeChange = () => {
    if (isDark === false) {
      localStorage.setItem("theme", "dark");
      document
        .getElementsByTagName("HTML")[0]
        .setAttribute("data-theme", localStorage.getItem("theme"));
        setIsDark(true);
    } else {
      localStorage.setItem("theme", "light");
      document
        .getElementsByTagName("HTML")[0]
        .setAttribute("data-theme", localStorage.getItem("theme"));
        setIsDark(false);
    }
  }

This method will get triggered when we toggle the theme from light to dark or vice-versa. It will update the state isDark based on current theme choosen and simultaneously update the data-theme attribute. data-theme attribute helps application to determine which color schemes need to applied either dark html[data-theme="dark"] or light html[data-theme="light"].

// templete for theme toggle button

  return (
    <label className="switch">
      <input
        type="checkbox"
        defaultChecked={isDark}
        onChange={() => toggleThemeChange()}
      />
      <span className="slider round" />
    </label>
  )

returning the html toggle element for switching the theme.

function App() {
  return (
    <div className="App">
      <header className="App-header">
        <img src={logo} className="App-logo" alt="logo" />
        <p>
          Edit <code>src/App.js</code> and save to reload.
        </p>
        <a
          className="App-link"
          href="https://reactjs.org"
          target="_blank"
          rel="noopener noreferrer"
        >
          <DarkModeToggle />
        </a>
      </header>
    </div>
  );
}

Add this DarkModeToggle component wherever you want to place it.