skip to Main Content

I’m working with React and I have a table that users can add and delete rows from. The table is made with an array of components. Each component/row has a trash can icon that when clicked executes the delete row function. It would seem that each component only has access to the old state of the array/table, and so deleting doesn’t work correctly. Any ideas how I could fix this issue?

An example of a component in the useState array that makes up this table:

<Row
  className={className}
  columns={columns}
  text={text}
  key={key}
  keyProp={key}
  deleteFunction={() => removeRow(key)}
/>

The delete function that is a prop for every row/component in the array:

function removeRow(key) {
  setMeals(meals.filter(i => i.props.keyProp !== key));
  // This should only remove the one row which had its trash can icon clicked.
  // If there's 10 rows and you click the trash can for row 4, rows 4-10
  // will be deleted.
  // If you click the trash can for row 7, rows 7-10 will be deleted and so on.
}

2

Answers


  1. Give this a try, I am confident it will resolve the issue.

    function removeRow(key) {
    // This updates the previous meal array whenever there's a removal in the meal array
     setMeals((prevMeals) => {
        return prevMeals.filter((meal) => meal.props.keyProp !== key)
    })
    

    Also, improve your Delete function as shown below:

    <Row className={className} columns={columns} text={text} key={key} keyProp={key} deleteFunction={() => removeRow.bind(null, key)} />
    
    Login or Signup to reply.
  2. As others pointed out, your problem is likely elsewhere in your code. Using a functional update is preferred, but I don’t think filter is the right choice to remove a known index from an array. Here’s a functioning demo for you to work from –

    function App() {
      const [rows, setRows] = React.useState(Array.from("ABCDEF"))
      
      const removeRow = index => event => {
        setRows(prev => prev.slice(0, index).concat(prev.slice(index + 1)))
      }
    
      return rows.map((key, index) =>
        <div key={key} onClick={removeRow(index)} children={key} />
      )
    }
    
    ReactDOM.createRoot(document.querySelector("#app")).render(<App />)
    div ~ div { margin-top: 0.5rem; }
    div > div { cursor: pointer; border: 1px solid silver; padding: 0.5rem }
    <script crossorigin src="https://unpkg.com/react@18/umd/react.development.js"></script>
    <script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
    <div id="app"></div>

    It is a common need to immutably remove an element from an array. You will likely benefit from separating this logic from your component to make it reusable in other parts of your program –

    function removeAt(arr, index) {
      return arr.slice(0, index).concat(arr.slice(index + 1))
    }
    
    
    function App() {
      const [rows, setRows] = React.useState(Array.from("ABCDEF"))
      
      const removeRow = index => event => {
        setRows(prev => removeAt(prev, index))
      }
    
      return rows.map((key, index) =>
        <div key={key} onClick={removeRow(index)} children={key} />
      )
    }
    
    ReactDOM.createRoot(document.querySelector("#app")).render(<App />)
    div ~ div { margin-top: 0.5rem; }
    div > div { cursor: pointer; border: 1px solid silver; padding: 0.5rem }
    <script crossorigin src="https://unpkg.com/react@18/umd/react.development.js"></script>
    <script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
    <div id="app"></div>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search