2

I am trying to increment the ID value useing the useState hook,but its not incrementing .I have to call the fct two times for the id to be incremented.I was able to see that by console log the object before and after the usestate but i found the result the same

function ToDoListApp() {
    const [noteList, setNoteList]=useState([])
    const [note,setNote]=useState({ noteId: 0 , txt: "", noteState: false })
    function addToList(e) {
        e.preventDefault();
        if(noteList.length===0){
            console.log(note)
            setNote({noteId: 0 , txt: note.txt ,noteState: false })
            setNoteList(noteList=>[...noteList,note])
        }else{
            console.log(note)
            console.log(noteList[noteList.length-1].noteId + 1)
            setNote({noteId:noteList[noteList.length-1].noteId + 1,txt:note.txt, noteState:false})
            setNoteList(noteList=>[...noteList,note])
            console.log(note)
            
        }
          
    }
    function deleteItemFromList(e,id){
        
        setNoteList(noteList.filter(note => note.noteId !== id ))
        console.log(noteList.length)
    }
    function handleTheNoteTxt(e) {
        e.preventDefault();
        setNote({
            ...note,
            txt:e.target.value
        })
        
      }


    const notesDiplay =noteList.map((note)=>
    <Stack key={note.noteId} direction="row" className="note-styling" justifyContent="center" alignItems="center" spacing={2}>
        <p>{note.txt} </p>
        <p>{note.noteId} </p>
        
        <Button onClick={e => deleteItemFromList(e,note.noteId)} variant="outlined" size='small' >X</Button>
        
    </Stack>
    )
  return (
    <div>
        <Stack direction="column" justifyContent="center" alignItems="center">
        <Stack className='note-app-container bg1' direction="column" justifyContent="flex-start" alignItems="center" spacing={2} >
            <div className='notes-input bg3'>
                <TextField autoFocus  label="Add your note" variant="standard" value={note.txt} 
                    onChange={handleTheNoteTxt}/>
                <Button variant="outlined" size='medium' onClick={addToList}>Add</Button>
            </div>
            <div className='notes-container bg3'>
            {notesDiplay}
            </div>
        </Stack>
        </Stack>     
    </div>
  )
}

export default ToDoListApp`
Christian Fritz
  • 20,641
  • 3
  • 42
  • 71

2 Answers2

1

Here is a fixed version with a little simplifying and refactoring.

import { useState } from 'react';
import { Stack, Button, TextField } from '@mui/material'

function ToDoListApp() {
    const [noteList, setNoteList] = useState([]);
    const [nextId, setNextId] = useState(1);
    const [value, setValue] = useState("")


    function addToList(e) {
        e.preventDefault();
        noteList.push({
            noteId: nextId,
            txt:  value,
            noteState: false
        })
        setNextId(val => val + 1);
        setValue("");
    }


    function deleteItemFromList(e, id) {

        setNoteList(noteList.filter(note => note.noteId !== id))
        console.log(noteList.length)
    }


    const notesDiplay = noteList.map((note) =>
        <Stack key={note.noteId} direction="row" className="note-styling" justifyContent="center" alignItems="center" spacing={2}>
            <p>{note.txt} </p>
            <p>{note.noteId} </p>
            <Button onClick={e => deleteItemFromList(e, note.noteId)} variant="outlined" size='small' >
                X
            </Button>
        </Stack>
    )

    return (
        <div>
            <Stack direction="column" justifyContent="center" alignItems="center">
                <Stack className='note-app-container bg1' direction="column" justifyContent="flex-start" alignItems="center" spacing={2} >
                    <div className='notes-input bg3'>
                        <TextField autoFocus label="Add your note" variant="standard"
                            onChange={(e) => setValue(e.target.value) } />
                        <Button variant="outlined" size='medium' onClick={addToList}>Add</Button>
                    </div>
                    <div className='notes-container bg3'>
                        {notesDiplay}
                    </div>
                </Stack>
            </Stack>
        </div>
    )
}

export default ToDoListApp

[EDIT - add'l info on reasoning]

  1. The comment from @ChristianFritz covers your actual bug - when you update with useState the new value is not actually reflected in the following line of code. I addressed that here with the nextId state variable, though there are plenty of other ways to do it.

  2. I noticed that you had the same note data in two places: once in the array, and once in the "note" state. That can only give you a headache later, so I got rid of the note state. You don't need it. If you want to allow for a selectedNote later (so you can add an editing feature, for example), use another state variable to keep the id of the note you want to save. Then employ "useMemo" to select it out. Let me know if it would be helpful to see that in full.

  3. Your addToList function can do the same thing regardless of if the noteList.length is 0 or more, so I removed the conditional logic and updated the logic to reflect the simplified state setup.

  4. Your "handleTheNoteTxt" function wasn't needed. To track the value of the TextField, you just need to update a text value in state. We can create a text value with useState, and use the value's set function for that. So that's where I added the "value" state, and put a setValue() call right into the TextField's onChange().

  5. Then we can have the "+" button call the addNote handler, and it'll be able to look at the "value" state to post the new note and update the state variables.

Aadmaa
  • 829
  • 5
  • 13
0

The link that Christian sent is useful for you to understand what's going on.

This is one way to solve it:

function addToList(e) {
    e.preventDefault();
    if (noteList.length === 0) {
      const newNote = { noteId: 0, txt: note.txt, noteState: false };
      setNote(newNote)
      setNoteList([...noteList, newNote])
    } else {
      const newNote = { noteId: noteList[noteList.length - 1].noteId + 1, txt: note.txt, noteState: false };
      setNote(newNote)
      setNoteList([...noteList, newNote])
    }
  }
Paulo Fernando
  • 3,148
  • 3
  • 5
  • 21
  • The solution you shared is working perfectly thank you a lot . But why do I need to create a new const newNote and not directly assign the value? What was wrong with my logic? – Yahia Bahhous Dec 01 '22 at 11:41