how to set and retrive localstorage object on certain conditions

Viewed 47

I am working on a dice game and i have a timer which is calculating total time taken to win the game. So i want to store that total time taken in localstorage and display later on the screen. Basically i want to store it in the local storage only if the time taken is less than previous time record(which i haven't worked on yet as i am struggling to set and get that local storage properly). I am facing issues while showing time taken on the UI which i am fetching from the localstorage.

Below is the code where i have initialized a state "const [recordTime, setRecordtime]" which is supposed to hold previous time taken value from local storage. Also localstorage which i am fetching is also getting run multiple times as shown in the below screenshot in the console output.

const [recordTime, setRecordtime] = useState(fetchPrevioustime())

function fetchPrevioustime(){
        const recordedTime = JSON.parse(localStorage.getItem(("recordTime")))
        console.log(recordedTime)
        //const recordedTimesc = localStorage.getItem(("recordTimesc"))
       if(recordedTime !== null){
            return{
                recordedTime
            }
        } 
    }

I have a useEffect which gets triggered when game is won(tenzies is holding won state below in my code) and sets the localstorage to current time taken and also sets above "recordTime" state.

useEffect(() => {
            if(tenzies){
               let temp1 = [{
                mn: mn,
                sc: sc
            }]
            localStorage.setItem("recordTime", JSON.stringify(temp1))
            setRecordtime(temp1)
        }    
    },[tenzies]
    )

Below are the constants where mn and sc are getting calculated and i am using these constant in above effect.

const mn = ("0" + Math.floor((timer / 60000) % 60)).slice(-2)
const sc = ("0" + Math.floor((timer / 1000) % 60)).slice(-2)
const mlsc = ("0" + ((timer / 10) % 100)).slice(-2)

Inside my return of function component i am displaying recordTime.sc to show the time taken. But this is currently showing as blank on the UI.

return (
        <main>
            <h1 className="title">Tenzies</h1> 
            <p className="instructions">Roll until all dice are the same. Click each die to freeze it at its current value between rolls.</p>
            <div className= "congrats" style={stylesWon}>Congrats! You have won the game. <br></br>
            You took {mn > 0 && `${mn}minutes and ` } {sc}  seconds.
           Your best time is {recordTime.sc}
            </div>
            <div className="display" style={stylesTimer}>
                <span>{mn}:</span>
                <span>{sc}:</span>
                <span>{mlsc}</span>
            </div><br></br>
            <div className="dice-container">
                {diceElements}
            </div>
            {/*<button className="roll-dice" onClick={rollDice}>{tenzies ? "New Game" : "Roll"}</button>*/}
            <button className="roll-dice" onClick={rollDice}>{buttonText()}</button>
            {tenzies && <Confetti />}
            
        </main>
    )
}

Below is the output screen - enter image description here

hoping to get some clarity about where i am doing things wrong.

1 Answers

You need to curry the function to use as initialiser for useState: See Docs This should work:

const [recordTime, setRecordtime] = useState(() => fetchPrevioustime());

You could also use an effect like this.

useEffect(() => {
       setRecordTime(JSON.parse(localStorage.getItem("recordTime")))  
})

Once the component mounts, and renders, this effect will run, then read and set the recordtime state prop.

If you were going to use a store like redux for example, this would also typically where you would dispatch the action to initialise state for the component. I would also tend to move things like read from LS to the actions/sagas - but that's a bit out of scope for the question.

Related