Search code examples
reactjs

What's the best way to set localStorage in React?


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?


Solution

  • 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>
        )
    }