I m working with localstorage. I have some toDos list(its name savedToDos in my code) there and now I m working on button that allows to save changes after editing values of toDos. I save changes in localStorage and then I try to update state to get fresh data from localstorage, but it is not working, changes are not showing correctly. It is working only when I reload page – all changes are showing correctly. Otherwise I’ve seen in console that localStorage is updating correctly, but when I try to update state with localStorage, state is just doesn’t updating, only after reload of page. And without reloading toDo list is showing incorrect updates.
Here is code, main thought in function saveToDo
export default function Bar() {
const LOCAL_TO_DOS = "localToDos"
const [toDo, setToDo] = React.useState("")
const [savedToDos, setSavedToDos] = React.useState([])
const barInput = document.getElementById("barInput")
const inputRef= React.useRef(null)
//localStorage.clear()
React.useEffect(()=>{
if(localStorage.getItem(LOCAL_TO_DOS)) {
setSavedToDos(
JSON.parse(
localStorage.getItem(LOCAL_TO_DOS)
)
)
}
}, [])
function handleChange(event){
setToDo(event.target.value)
}
function addNewToDo(){
if(toDo){
const localToDo = {
id: nanoid(),
content: toDo
}
setSavedToDos([...savedToDos ,localToDo])
localStorage.setItem(
LOCAL_TO_DOS,
JSON.stringify([...savedToDos,localToDo])
)
setToDo("")
barInput.value = ""
inputRef.current.focus()
}
}
function editToDo(event){
//if were changes
document.getElementById(event.target.parentNode.id)
.contentEditable="true"
document.getElementById(event.target.id)
.style.visibility = "hidden"
document.getElementById(event.target.id)
.nextElementSibling.style.visibility = "visible"
}
function saveToDo(event){
document.getElementById(event.target.parentNode.id)
.contentEditable="false"
document.getElementById(event.target.id)
.style.visibility = "hidden"
document.getElementById(event.target.id)
.previousElementSibling.style.visibility = "visible"
const editedToDo = {
id: event.target.parentNode.id,
content: document.getElementById(
event.target.parentNode.id
).childNodes[0].nodeValue
}
let updatedToDos = savedToDos.filter(note =>
note.id != event.target.parentNode.id
)
localStorage.setItem(
LOCAL_TO_DOS,
JSON.stringify([editedToDo,...updatedToDos])
)
setSavedToDos(
JSON.parse(localStorage.getItem(LOCAL_TO_DOS))
)
}
return (
<div className='bar'>
<textarea
ref={inputRef}
id="barInput"
//type="text"
placeholder="new to-do"
onChange={handleChange}
/>
<button id="addButton" onClick={addNewToDo}>add</button>
{savedToDos.length != 0? <>
{savedToDos.map((savedToDo)=>(
<div className="toDoArea" id={savedToDo.id}>
{savedToDo.content}
<button id={nanoid()} className="editButton" onClick={editToDo}>edit</button>
<button id={nanoid()} className="saveButton" onClick={saveToDo}>save</button>
<button id={nanoid()} className="deleteButton" onClick={deleteTodo}>delete</button>
</div>
)) }</> : <p>You have not any tasks</p>}
</div>
)
}
>Solution :
It’s updating correctly on reload because your useEffect is correctly fetching the updated values from localStorage, but in your saveToDo function, you should set the value directly instead of trying to refetch from localStorage. i.e.
setSavedToDos([editedToDo,...updatedToDos])
So your function should look like this:
function saveToDo(event){
document.getElementById(event.target.parentNode.id).contentEditable="false"
document.getElementById(event.target.id).style.visibility = "hidden"
document.getElementById(event.target.id).previousElementSibling.style.visibility = "visible"
const editedToDo = {
id:event.target.parentNode.id,
content:document.getElementById(event.target.parentNode.id).childNodes[0].nodeValue
}
let updatedToDos = savedToDos.filter(note => note.id != event.target.parentNode.id)
localStorage.setItem(LOCAL_TO_DOS, JSON.stringify([editedToDo,...updatedToDos]))
setSavedToDos([editedToDo,...updatedToDos])
}
That should update the array correctly. The localStorage item should just be to ensure that your to-do list is still available on reloading the page.