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