0

When you first run the component, it should display "1", and on button click, append it by 3, which it does. Value inside localstorage also changes, but when i reload the page, localstorage changes again to 1... what am i missing?

import { useState, useEffect } from 'react'

function Test() {
    
    const [testNum, setTestNum] = useState(1);

    useEffect(() => {
        const data = window.localStorage.getItem("MY_TEST_ITEM");
        setTestNum(JSON.parse(data));
    }, []);

    useEffect(() => {
        window.localStorage.setItem("MY_TEST_ITEM", JSON.stringify(testNum))
    }, [testNum]);

    

  return (
    <div>
        <h1>{testNum}</h1>
        <button onClick={() => { setTestNum(testNum + 3) }}>Add</button>
    </div>
  )
}

export default Test
marko2304
  • 17
  • 4
  • 2
    `useEffect` always runs on initial render and if there are dependencies also runs everytime they change. In your case you don't want to run initially, but only when `testNum` changes. You can't control this with the useEffect alone, you must create a condition check inside. But I would say a better solution would be to set `localStorage` directly in your `onClick` event instead of setting af state and rely on `useEffect` to set it. – Bqardi Oct 23 '22 at 10:53

3 Answers3

1

try this instead :

const [testNum, setTestNum] = useState(window.localStorage.getItem("MY_TEST_ITEM") === null ? 1 : window.localStorage.getItem("MY_TEST_ITEM"));
1

Every time you reload your page your state refreshes.

You have testNum set to 1 so every render it will be set to that.

const [testNum, setTestNum] = useState(1);

Then you have these useEffects running at the same time

    useEffect(() => {
    const data = window.localStorage.getItem("MY_TEST_ITEM");
    setTestNum(JSON.parse(data));
}, []);

  useEffect(() => {
    window.localStorage.setItem("MY_TEST_ITEM", JSON.stringify(testNum))
}, [testNum]);

The second useEffect will render before the first one, thus setting the localStorage to 1.

UseEffect is actually not needed in this case. Try this;

const storageValue = window.localStorage.getItem("MY_TEST_ITEM";
const [testNum, setTestNum] = useState(storageValue ?? 0 );

updateLocalStorageFunc(value){
   setTestNum(value)
   window.localStorage.setItem("MY_TEST_ITEM", JSON.stringify(testNum))
}
    


return (    
<div>
    <h1>{testNum}</h1>
    <button onClick={() => { updateLocalStorageFunc(testNum + 3) }   
</div>)
leantrim
  • 21
  • 2
0

Basically you are saying give "testNum" the value 1 on every page refresh, that means your local storage will be always updated to the initial value on the refresh which is 1. So the solution is very obvious, all what you need to do is change the initial state value which should be the localStorage value not the hard coded value. enter image description here

const [loading, setLoading] = useState(true)
const [testNum, setTestNum] = useState(null)
const intialValue = 1

useEffect(() => {
    const localStorageValue = window.localStorage.getItem("YOUR_ITEM_KEY") || intialValue
    setTestNum(Number(localStorageValue))
    setLoading(false)
}, [])

useEffect(() => {
    testNum !== null && window.localStorage.setItem("YOUR_ITEM_KEY", testNum)
}, [testNum])

if(loading) return <div>Loading ...</div>
return(
    <>
        <div>testNum: {testNum}</div>
        <button onClick={e => setTestNum(testNum + 3)}>increment testNum by 3</button>
    </>
)

You can also use the useMemo hook to avoid any unnecessary re-renders