skip to Main Content
const [item, setItem] = useState("")
const [itemList, setItemList] = useState([])
const [actualItem, setActualItem] = useState([])

function addItem(){
    setItemList([...itemList , item])
    setActualItem([...itemList , item])
    setItem("")
}

function filterVal(e){
    const filteredArr = itemList.filter((item)=> item.includes(e.target.value))
    if (filteredArr.length !== 0 && e.target.value.length > 3) {
        setItemList(filteredArr)    
    } else {
        setItemList(actualItem)
    }
}

console.log("render")

function removeItem(e){
    const val = itemList.indexOf(e.target.parentElement.firstElementChild.innerText)
    itemsArr = itemList 
    itemsArr.splice(val, 1)
    console.log(itemsArr)
    setItemList(itemsArr)
}

return (
    <div className="body">
        <div className="search">
        <input type="text" onChange={filterVal} placeholder="Search Here"/>
    </div>
    <div className="addItem">
        <input type="text" placeholder="Add here" value={item} onChange={(e)=>{setItem(e.target.value)}}/>
        <button className="btn" onClick={addItem}>Add Item</button>
        <ul className="display">
            {
                itemList.length === 0 ? <h1>No Items</h1> : 
                itemList.map((item, index)=>{
                    return (
                        <div className="li" key={index} id={index}>
                            <li>{item}</li>
                            <p onClick={removeItem}>✖</p>
                        </div>
                    )
                })
                }
        </ul>
        <button className="clearBtn" onClick={()=>{setItemList([]); setActualItem([])}}>Clear All</button>
    </div>
    </div>
)

I am building a todo list using react. Adding, clear all and search functionality are working fine. But the removeItem is not working. When i click on the cross button, it should splice the array of items and update the actual state. But it is not. The state is updating but it is not getting reflected in the map function

2

Answers


  1. Maybe you can try this code instead

    const removeItem = (e) => {
            const val = itemList.indexOf(e.target.parentElement.firstElementChild.innerText)
            setItemList(itemList.filter(item => item !== val)
        
    }
    
    Login or Signup to reply.
  2. Your code is almost working, but the issue happens at how JS compares objects/arrays.

    In your removeItem method, you have the right thinking to copy the value of the state itemList to a temporary value itemArr. HOWEVER, what you did here is actually copied the reference/address of the itemList, and is mutating it directly (which is a bad practice, but you had the right idea according to how you code, so thumbs up for that).

    When the state is updated in setItemList(itemsArr), React makes a comparison of the state’s itemList, turns out the value that you have previously passed in in setItemList is exactly the same!

    (See "Referential Equality" section of this article for more info https://dmitripavlutin.com/how-to-compare-objects-in-javascript/#1-referential-equality)

    What you are supposed to do is, declare a new variable, COPY the value of the itemList instead of the reference, run your logic, then finally set the state with setItemList(itemsArr); so React will realize that the value of the state itemList has actually been updated, and finally cause a rerender, updating the UI.

    This is the fix to your removeItem method —

      function removeItem(e) {
        const val = itemList.indexOf(
          e.target.parentElement.firstElementChild.innerText
        );
        const itemsArr = [...itemList]; // <-- this is important part
        itemsArr.splice(val, 1);
        console.log(itemsArr);
        setItemList(itemsArr);
      }
    

    See your work in action in CodeSandbox — https://codesandbox.io/s/great-marco-f4pkd5?file=/src/App.tsx

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search