Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React, localStorage is not persistent upon page refresh

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;
like image 710
TaFran Avatar asked Aug 15 '26 09:08

TaFran


2 Answers

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 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);
  }
}, []);
like image 52
yousoumar Avatar answered Aug 17 '26 22:08

yousoumar


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!' } ])
like image 41
Evren Avatar answered Aug 17 '26 22:08

Evren



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!