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;
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);
}
}, []);
Collected from the Internet
Please contact [email protected] to delete if infringement.
Comments