I'm trying to start learning react but fail understanding basic logic. I have a todo list page, which works fine with a strike-through, but if I try to change the strike through to REMOVE instead, my app disappears on click. Here's my code, hopefully you can understand:
function Note({ notes, note, onClickSetter }) {
const { input, id } = note
const [strikeThrough, setStrikeThrough] = useState(false);
function onNoteClick(event) {
const { value, id } = event.target
//setStrikeThrough((prev) => !prev) - the strike through which is canceled right now
onClickSetter(prev => prev.filter(aNote => aNote.id !== id)) // why this doesn't work?
}
return (
<>
<h1 style={ strikeThrough ? {textDecoration: 'line-through'} : { textDecoration: 'none' }} id={id} onClick={onNoteClick}>{input}</h1>
</>
)
}
a little explanation on my props: notes - literally the list of notes which comes from a useState on father component (we shouldn't touch this from my understanding of react)
note - self note information
onClickSetter - the other part of useState, the setter one.
So on another words, I have the notes which holds all notes, and onClickSetter which is in another words is setNotes - both part of useState
on top of that I have a note information, because this is a note component
the father component:
function Body() {
const [Notes, setNotes] = useState([])
return (
<div className='notes-body'>
<NewNote onClickSetter={setNotes}/>
{Notes.map((note) => { return <Note key={note.id} notes={Notes} note={note} onClickSetter={setNotes}/>})}
</div>
)
}
function NewNote({ onClickSetter }) {
const [input, setInput] = useState('')
function onInputChange(event) {
const { value } = event.target
setInput(value)
}
function onButtonClick(event) {
onClickSetter((prev) => {
try {
return [...prev, {input: input, id: prev[prev.length-1].id 1}]
}catch{
return [{input: input, id: 0}]
}
})
setInput('')
}
return (
<>
<Input placeholder="add new note" className='note-text' onChange={onInputChange} value={input}/>
<Button className='btn btn-primary add-note' onClick={onButtonClick} />
</>
)
}
CodePudding user response:
The reason is that event.target.id
is a string
representing a number since all HTML attributes has the string type. Whilst in your data structure, the ID is a number
. So, e.g. "1"
vs 1
. This can be hard to spot sometimes.
The easiest way to fix this is to add a parseInt
to the right place to convert the string to a number:
onClickSetter((prev) => prev.filter((aNote) => aNote.id !== parseInt(id)))
However, I also want to mention (and this is more advanced stuff but I like to get people on the right track :) ) that really, you shouldn't pass the whole setter down into the child component, but instead a callback called something like onRemoveNote
that accept the note id and the actual filtering/removal would happen in the parent component.
This would be better placement of concerns. For now though, the above will work and I can help you out on stack overflow chat if needed :).