Home > database >  How do I set a state to a value in localStorage?
How do I set a state to a value in localStorage?

Time:01-22

There is a button that toggles dark and light mode, and the state of what mode the page is on is saved in localStorage. However, I cannot change the initial value of the state (dark) and I don't know why. This is done in a useEffect function but no matter what the value of dark is, it is always set to its initial value of false.

How do I set the value of the localStorage to the dark state?

function Mode() {
    const [dark, setDark] = useState(false);

    // localStorage.removeItem("dark");

    const onClick = () => {
        if (dark) {
            setDark(false);
            document.querySelector("body").classList.remove("dark");
        } else {
            setDark(true);
            document.querySelector("body").classList.add("dark");
        }
        localStorage.setItem("dark", dark);
    };

    const localDark = JSON.parse(localStorage.getItem("dark"));

    useEffect(() => {
        if (localDark !== null) {
            setDark(!JSON.parse(localStorage.getItem("dark"))); // this is what does not change the value of dark
            onClick();
        }
    }, []);

    return (
        <div onClick={onClick} className="mode">
            {dark ? <Light /> : <Dark />}
        </div>
    );
}

CodePudding user response:

Directly use the value from localStorage in useState as the default. useEffect is unnecessary here.

const [dark, setDark] = useState(JSON.parse(localStorage.getItem("dark")));
document.body.classList.toggle('dark', dark);

The click event handler should set the localStorage dark value to the logical complement of the current value.

const onClick = () => {
    localStorage.setItem("dark", !dark);
    setDark(!dark);
};

CodePudding user response:

Use a function to initialize the state from local storage. Update the storage and the body's class on init, and when dark state changes:

const getLocalDark = () => !!JSON.parse(localStorage.getItem("dark"));

function Mode() {
  const [dark, setDark] = useState(getLocalDark);

  const onClick = () => {
    setDark(d => !d);
  };

  useEffect(() => {
    const classList = document.querySelector("body").classList;
    
    if (dark) classList.add("dark");
    else classList.remove("dark");
    
    localStorage.setItem("dark", dark);
  }, [dark]);

  return (
      <div onClick={onClick} className="mode">
          {dark ? <Light /> : <Dark />}
      </div>
  );
}

CodePudding user response:

To set the value of localStorage to the dark state, you need to set the value of dark to true in your useEffect function.

useEffect(() => {
    if (localDark !== null) {
        setDark(true); // set dark to true
        onClick();
    }
}, []);

CodePudding user response:

Perhaps you'd be interested in a useLocalStorage hook. Here's how that can be implemented:

export const useLocalStorage = (key, initialState) => {
    const [value, setValue] = useState(() => {
        // Initialize with the value in localStorage if it
        // already exists there.
        const data = localStorage.getItem(key);

        // Otherwise, initialize using the provided initial state.
        return data ? JSON.parse(data) : initialState;
    });

    // Each time "value" is changed using "setValue", update the
    // value in localStorage to reflect these changes.
    useEffect(() => {
        localStorage.setItem(key, JSON.stringify(value));
    }, [value]);

    return [value, setValue];
};

This hook syncs the value seen in localStorage with the value stored in memory under the value variable.

The usage looks like this (almost identical to regular useState):

export const Counter = () => {
    const [count, setCount] = useLocalStorage('count', 0);

    return (
        <div>
            <p>{count}</p>
            <button
                onClick={() => {
                    setCount((prev) => prev   1);
                }}>
                Increase count
            </button>
        </div>
    );
};

However, the main caveat of this hook is that it's only really meant to be used in one component. That means, if you change the value from light to dark in one component using this hook, any other components using it won't be updated. So instead, you should look into using a similar implementation of what is demonstrated above, but using the React Context API. That way, you'll ensure your in-memory values are in sync with those stored in localStorage. Theming is one of the main uses of the Context API.

Good luck! :)

  • Related