Home > Back-end >  What's the best way to set localStorage in React?
What's the best way to set localStorage in React?

Time:03-09

I'm building a game and I would like to store the user's wins and losses in the browser's local storage. I have a simple component that looks like this:

import { useState, useEffect } from 'react';

const Game = () => {
    const [wins, setWins] = useState(0);
    const [losses, setLosses] = useState(0);


    // Report wins to localStorage
    useEffect(() => {
        localStorage.setItem('wins', wins);
    }, [wins]);

    // Report losses to localStorage
    useEffect(() => {
        localStorage.setItem('losses', losses);
    }, [losses]);

    // Get any existing data in localStorage
    useEffect(() => {
        const winCount = localStorage.getItem('wins');
        const lossCount = localStorage.getItem('losses');

        winCount ? setWins(winCount) : setWins(0);
        lossCount ? setLosses(lossCount) : setLosses(0);
    }, []);


    return (
        <div className="game">
            Wins: {wins} | Losses: {losses}

            <-- Game Stuff Here -->
            <-- Wins & Losses Get Incremented During Game -->
        </div>
    )
}

The problem is that upon rendering, the first two useEffect's run and reset the localStorage with zeros. I know there is a workaround using useRef to stop a useEffect from running on the first render, but it feels a bit gimmicky. Is that the only solution or is there a better practice on not overriding the localStorage upon rendering?

CodePudding user response:

I would even go as far to say you don't need to get the localStorage each time you rerender the component.


// Get any existing data in localStorage

const winCount = () => Number(localStorage.getItem('wins')) || 0;
const lossCount = () => Number(localStorage.getItem('losses')) || 0;


const Game = () => {
    const [wins, setWins] = useState(winCount());
    const [losses, setLosses] = useState(lossCount());


    // Report wins to localStorage
    useEffect(() => {
        localStorage.setItem('wins', wins);
    }, [wins]);

    // Report losses to localStorage
    useEffect(() => {
        localStorage.setItem('losses', losses);
    }, [losses]);

    return (
        <div className="game">
            Wins: {wins} | Losses: {losses}

            <-- Game Stuff Here -->
            <-- Wins & Losses Get Incremented During Game -->
        </div>
    )
}

CodePudding user response:

Solved!

There is no need to get the localStorage values in the useEffect. We can simply get them when setting the state values.

My component now looks like this:

import { useState, useEffect } from 'react';

const Game = () => {
    const [wins, setWins] = useState(() => {
        const storageWins = localStorage.getItem('wins');
        return storageWins ? parseInt(storageWins) : 0;
    );
    const [losses, setLosses] = useState(() => {
        const storageLosses = localStorage.getItem('losses');
        return storageLosses ? parseInt(storageLosses) : 0;
    );


    // Report wins to localStorage
    useEffect(() => {
        localStorage.setItem('wins', wins);
    }, [wins]);

    // Report losses to localStorage
    useEffect(() => {
        localStorage.setItem('losses', losses);
    }, [losses]);


    return (
        <div className="game">
            Wins: {wins} | Losses: {losses}

            <-- Game Stuff Here -->
            <-- Wins & Losses Get Incremented During Game -->
        </div>
    )
}
  • Related