Home > Back-end >  React, localStorage is not persistent upon page refresh
React, localStorage is not persistent upon page refresh

Time:06-17

I'm new to React and I can't understand what's wrong with my use of the useEffect hook. The code is compiled successfully and everything seems to work. The components added by the user are shown on the browser and added to localStorage but upon refresh, only the example component is shown (Box 1) and the input done by the user is lost. Any idea on what could be the issue?

mport React, { Fragment, useState, useRef, useEffect } from 'react';
import { v4 as uuidv4} from 'uuid';
import { BoxList } from './components/BoxList';
import { SearchBox } from './components/SearchBox';

const KEY = "boxApp.boxes";

export function App() {
  const [boxes, setBoxes] = useState([ {id: 1, title: 'Box 1', content: 'This is just an example of a box, remove it and create yours!' } ])
  
  const boxTitleRef = useRef();
  const boxContentRef = useRef();

  useEffect(() => {
    const storedBoxes = JSON.parse(localStorage.getItem(KEY));
    if (storedBoxes) {
      setBoxes(storedBoxes);
    }
  }, []);

  useEffect(() =>{
    localStorage.setItem(KEY, JSON.stringify(boxes));
  }, [boxes]);

  const removeBox = (id) => {
    const remainingBoxes = boxes.filter((box) => box.id !== id);
    setBoxes(remainingBoxes);
  }

  const addNewBox = (evt) => {
    evt.preventDefault();
    const boxTitle = boxTitleRef.current.value;
    const boxContent = boxContentRef.current.value;
    if (boxTitle === '' || boxContent === '') return;
    setBoxes( previousBoxes => {
      return ([...previousBoxes, { id: uuidv4(), title: boxTitle, content: boxContent}])
    });

    boxTitleRef.current.value = null;
    boxContentRef.current.value = null;
  }

  return (
    <Fragment>
      <SearchBox  />
      <div>
        <h2>Add a box</h2>
        <form>
         <input type='text' placeholder='Title' ref={boxTitleRef}></input>
          <input type='text' placeholder='Content' ref={boxContentRef}></input>
          <button type='submit' onClick={addNewBox}>➕</button>
        </form>
      </div>
      <BoxList boxes={boxes} removeBox={removeBox}/>
    </Fragment>
  );
}

export default App;

CodePudding user response:

The problem is coming from the below useEffect that you have:

useEffect(() =>{
   localStorage.setItem(KEY, JSON.stringify(boxes));
}, [boxes]);

It updates the localStorage every time boxes changes, but also when the component gets mounted the first time, and at this point boxes is equal to that initial state given to useState. You could remove it, and update the localStorage when adding adding and removing items:

const addNewBox = (evt) => {
  evt.preventDefault();
  const boxTitle = boxTitleRef.current.value;
  const boxContent = boxContentRef.current.value;
  if (boxTitle === "" || boxContent === "") return;
  const newBoxes = [...boxes, { id: uuidv4(), title: boxTitle, content: boxContent }];
  setBoxes(newBoxes);
  localStorage.setItem(KEY, JSON.stringify(newBoxes));
  boxTitleRef.current.value = null;
  boxContentRef.current.value = null;
};
const removeBox = (id) => {
  const remainingBoxes = boxes.filter((box) => box.id !== id);
  localStorage.setItem(KEY, JSON.stringify(remainingBoxes));
  setBoxes(remainingBoxes);
};

You coud also change your useState call to this:

const [boxes, setBoxes] = useState(JSON.parse(localStorage.getItem(KEY)) || [ {id: 1, title: 'Box 1', content: 'This is just an example of a box, remove it and create yours!' } ]);

And remove the following useEffect that you have:

useEffect(() => {
  const storedBoxes = JSON.parse(localStorage.getItem(KEY));
  if (storedBoxes) {
    setBoxes(storedBoxes);
  }
}, []);

CodePudding user response:

It should solve your problem if you set your initial state value conditionaly from local storage like this.

Here is the piece you need to update

const initialValue = JSON.parse(localStorage.getItem(KEY));
const [boxes, setBoxes] = useState(initialValue ? initialValue : [ {id: 1, title: 'Box 1', content: 'This is just an example of a box, remove it and create yours!' } ])
  • Related