Karan Kumar
Karan Kumar

Reputation: 3176

React: Unable to filter list of components

I am trying to have a list of table fields which can be added and removed at any time.

Issue

As soon as I click delete any element in the middle(except the last one), it deletes all items underneath it

Code is here

I am not sure what is it that's doing wrong, it removes all the elements, even if I try to delete a specific one.


Adding code here also

import React, { useState } from 'react';
import { v4 as uuidv4 } from 'uuid';

const ListComponent = ({ remove, id }) => {
  return (
    <tr>
      <td>
        <input />
      </td>
      <td><button onClick={() => remove(id)}>Delete</button></td>
    </tr>
  )
}

const App = () => {
  const [array, setArray] = useState([]);
  const remove = (itemId) => {
    setArray(array.filter(each => each.id !== itemId))
  }
  const addListComponent = () => {
    let id = uuidv4();
    setArray(oldArray => [...oldArray, {
      id,
      jsx: <ListComponent key={id} id={id} remove={remove}/>
    }])
  }
  return (
    <div>
      <button onClick={addListComponent}>Add ListComponent</button>
      {array.length > 0 && array.map(each => each.jsx)}
    </div>
  )
}

export default App;

Upvotes: 0

Views: 47

Answers (1)

buzatto
buzatto

Reputation: 10382

the issue is everytime you create a new element a new remove function is created with reference to that current state in time. When you create an element, you create a jsx with a remove pointing to that array reference specific in time.

You could fix that changing your remove function to something like:

  const remove = (itemId) => {
    setArray(prevArr => prevArr.filter(each => each.id !== itemId))
  }

which would ensure that you will always have the correct reference to the current state.

Although that solves the issue, I would suggest to follow the guidelines and only store the necessary information at your state, and pass it to JSX at render when you map:

const App = () => {
  const [array, setArray] = useState([]);
  const remove = (itemId) => {
    setArray(array.filter(each => each.id !== itemId))
  }
  const addListComponent = () => {
    let id = uuidv4();
    setArray(oldArray => [...oldArray, { id }])
  }
  return (
    <div>
      <button onClick={addListComponent}>Add ListComponent</button>
      {array.length > 0 && array.map(({ id }) => <ListComponent key={id} id={id} remove={remove}/>)}
    </div>
  )
}

Upvotes: 2

Related Questions