React useEffect and localStorage doesn’t set state that is required in child components

I’ve got an app with rudimentary localStorage saving working, but I’m running into a problem when trying to load that data.

const defaultSaveState="default";
const [currentSave, setCurrentSave] = useState(defaultSaveState);
useEffect(() => {
  setCurrentSave(JSON.parse(localStorage.getItem("save")) // 'saved data'
}, [])
console.log(currentSave); // outputs 'default'

This runs in the parent component and the currentSave state is passed to a couple children components. I’m aware that useEffect is run after the component is rendered, which apparently means the children components are fully rendered before the parent, as the children components will render the data from defaultSaveState instead of the data loaded from localStorage. Even other variables in the parent component won’t get the updated data since they’re also populated before the component is rendered.

My question is what would be best practice to load localStorage once on page load and pass the data to child components correctly? I only want to load the data once, calling a load function outside of useEffect((),[]) doesn’t seem like a good idea, but I’m still learning React so I’m sure I’m missing something.

EDIT: I made up a minimal example to add and found that it works as it should, re-rendering the component with the correct values after load. I’ve narrowed down the issue I’m having to a couple of context components that are initializing with the default values but not updating to the loaded values, and I think I can work on getting that to update correctly after load.

  • 1

    Can you expand this to a minimal reproducible example which can be tested and observed? Is localStorage even needed in the first place? Passing values to child components can be done via props, useContext, etc. It’s not entirely clear what overall problem needs to be solved.

    – 

  • note that setCurrentSave only changes the value of currentSave at the top of the next render. As written, this appears to only render one time, and I would expect that currentSave would have the value “default” based on what you have. This shouldn’t interfere with your ability to pass the value to child components. Putting currentSave in the dependency list will cause a re-render.

    – 

  • @dustincarr OP’s code will render (at least) twice unless the value in localStorage is literally the string "default"

    – 




Why not to set state initially with storage item?

const [currentSave, setCurrentSave] = useState(() => JSON.parse(localStorage.getItem("save"));

console.log(currentSave); // outputs item saved in locastorage under "save" key.

Leave a Comment