2

I'm new working with ReactJS, I started a project a simple CRUD just for practice. So, I have a table and I want to add a class so that this element disappears when I press a button

The problem is when I press the button delete, React adds a class to all elements, disappearing all of them

How to delete only the parent element of a clicked button ? I tried to get the id of an event but I don't know how to specify to what element I want to add a class.

deleteTask(e, id){
  //let trDelete = 
  e.currentTarget.parentNode.getAttribute('key');
  M.toast({html: 'Task Deleted'})
  const currState = this.state.active;
  this.setState({active: !currState});

    }
{
this.state.tasks.map(task => {
    return (
        <tr data-key={task._id} key={task._id}  className={this.state.active ? "scale-transition scale-out": ""}>
            <td>{task.title}</td> 
            <td>{task.description}</td>
            <td>
                <button className="btn light-blue darken-4" onClick={(e) => this.deleteTask(e, task._id)}>
                    <i className="material-icons">
                        delete
                    </i>
                </button>
                <button className="btn light-blue darken-4" style={{margin: '4px'}}>
                <i className="material-icons">
                        edit
                    </i>
                </button>
            </td>
        </tr>
    )
  })
 }

2 Answers 2

2

To apply CSS classes on a per-item basis, you will need to track the class(es) of each item by adding extra component state.

A simple solution here would be to update your deleteTask() function:

deleteTask = (event, taskId) => { 

    this.setState(state => {

        /* 
        Iterate each task in state, and add isDeleted to task(s) with matching id 
        */
        return { 
            tasks : state.tasks.map(task => 
            (taskId === task._id ? { ...task, isDeleted : true } : { ...task }))
        };

    }, () => {

        /*
        Show toast popup after stat change
        */
        M.toast({html: 'Task Deleted'});
    });
}

And then update your table rendering to account for the new isDeleted item state:

<tr data-key={task._id} key={task._id}  
    className={ task.isDeleted ? "scale-transition scale-out": ""}>
    { /* Existing table markup */ }
</tr>
Sign up to request clarification or add additional context in comments.

5 Comments

Nice, but I get this warning when I delete an element Warning: Each child in a list should have a unique "key" prop.
You're welcome, interesting - what else is happening in your deleteTask() function? Are any items in the tasks array being duplicated?
@JORGE just updated answer based on your updates - does this help?
I have problems using triple dot operator in my project, there an alternative way to use it ?
Sorry to come back to you so late - glad I could help 😊
0

The class is being added to all of them, because you're iterating over each item and assigning the class to each task item based on active being constant.

If you want to delete or hide a task, the setState should be affecting this.state.tasks and not this.state.active.

I'm guessing your update and state is intended to look more like this:

deleteTask(e, id) {

  // Return new task objects to prevent mutation of state
  const tasks = this.state.tasks.map(task => {
    return task.id === id ? {...task, active: !task.active} : {...task};
  });

  // Executes callback after state update is complete
  this.setState({tasks}, () => M.toast({html: 'Task Deleted'}));
}

Disclaimer: I don't know what you're using to transpile, so you might have to use the equivalent of the object spread and property shorthand.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.