skip to Main Content

I have a React component that toggles a boolean when a button is clicked. It also successfully console logs the correct message when the button is clicked. But, it does not change the h2 element being returned. Why does this happen and how can I fix it? I research so far only brings up situations regarding state. Thank you.

function Heading() {
  let darkModeOn = false;
  const darkMode = <h2>Dark mode is on.</h2>;
  const lightMode = <h2>Light mode is on.</h2>;
  const handleMode = () => {
    darkModeOn = !darkModeOn;
    if (darkModeOn) {
      console.log("Darkmode is on.");
    } else {
      console.log("Lightmode is on.");
    }
  };
  return (
    <div>
      {darkModeOn ? darkMode : lightMode}
      <button onClick={handleMode}>Click me</button>
    </div>
  );
}

export default Heading;

/// Updated code with the below that uses useState hook

import { useState } from "react";

const Mode = () => {
  const [darkModeOn, setDarkMode] = useState(false);
  let mode = "";
  const handleMode = () => {
    console.log("button clicked...");
    setDarkMode(!darkModeOn);
    if (darkModeOn) {
      mode = "Dark mode";
    } else {
      mode = "Light mode";
    }
  };

  return (
    <>
      <h2>{mode} is on.</h2>
      <button onClick={handleMode}>Click to change mode.</button>
    </>
  );
};

export default Mode;

3

Answers


  1. Please do it like the below:

    const Mode = () => {
      const [mode, setMode] = useState('light');
      const handleMode = () => {
        console.log("button clicked...");
        if (mode === 'light') setMode('dark')
        else setMode('light')
      };
    
      return (
        <>
          <h2>{mode} is on.</h2>
          <button onClick={handleMode}>Click to change mode.</button>
        </>
      );
    };
    
    

    You should use useState to force rerender the component with the new state.
    the way you did doesn’t trigger the component rerender.

    More info:
    https://beta.reactjs.org/reference/react/useState#ive-updated-the-state-but-logging-gives-me-the-old-value

    Login or Signup to reply.
  2. Try this:

    import { useState } from "react";
    
    const Mode = () => {
      const [darkModeOn, setDarkMode] = useState(false);
    
      const handleMode = () => {
        setDarkMode(!darkModeOn);
      };
    
      return (
        <>
          <h2>{darkModeOn ? "Dark Mode" : "Light Mode"} is on.</h2>
          <button onClick={handleMode}>Click to change mode.</button>
        </>
      );
    };
    
    export default Mode;
    

    Or, you can also use the following code, where mode is also a state variable.

    import { useState } from "react";
    
    const Mode = () => {
      const [darkModeOn, setDarkMode] = useState(false);
      const [mode, setMode] = useState("Light Mode");
      const handleMode = () => {
        console.log("button clicked...");
        // this means that currently `darkModeOn` is true so we must convert it to Light mode
        if (darkModeOn) {
          setMode"Light mode");
        } else {
          setMode("Dark mode");
        }
        setDarkMode(!darkModeOn);
      };
    
      return (
        <>
          <h2>{mode} is on.</h2>
          <button onClick={handleMode}>Click to change mode.</button>
        </>
      );
    };
    
    export default Mode;
    
    Login or Signup to reply.
  3. I can see two issues in the code.

    The first :

    You are expecting darkModeOn to be updated immediately after setDarkMode(!darkModeOn) so just after this line you do this :

    if (darkModeOn) {
          mode = "Dark mode";
     } else {
         mode = "Light mode"
     }
    

    but, again, this is not how react works, when you run a code to update a state, only when this code finishes execting the component rerenders and only then, the state will be updated, so at the moment the if statement is executed the new value of darkModeOn is not available yet (because the component didn’t rerendered yet).

    The second:

    As it is said, when you updae a state like you are doing inside the handleMode function the component rerenders and in this new render mode will be initilized again to '' so doing so is really useless, you don’t even need this mode variable.

    You can simply display inside your JSX based on the value of darkModeOn

    //...
    const handleMode = () => {
      console.log("button clicked...");
      setDarkMode(!darkModeOn);
    };
    //....
    return (
        <>
          <button onClick={handleMode}>Click to change mode.</button>
          {darkModeOn ? <div>we are in the dark mode </div> : <div> we are in the light  mode </div>}
        </>
     );
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search