-2

TL;DR; Wrong elements from array get removed inside state array.

I've made a gridbuilder where people can add and remove grids from the screen. Currently people can add Papers with some random default text for testing purposes. The problem I have is that first of all when you hover over one element all the delete icons show up instead of just one for the current element. The other problem is that the wrong element gets deleted when user clicks the remove icon.

I have tried searching the web for removing the proper element from state array and found the following. Let's say you have an empty state:

this.state = {
  action: []
}

to push to an array inside the state I use the following method:

updateAction = (newAction) => {
  this.setState({action: [...this.state.action, newAction]});
};

now the question is how to remove the right element. I use the following:

removeElement = (id) => {
    this.setState({action: this.state.action.filter((value) => value !== id)});
    setTimeout(() => {
      console.log(`removeElement function: ${this.state}`);
    }, 400)
  };

This might seem a little unclear please refer to this CodeSandbox. Edit Material demo

Ezrab_
  • 825
  • 5
  • 19
  • 44
  • 1
    *"please refer to this CodeSandbox"* Your whole question (including any necessary code) has to be **in** your question, not just linked. Two reasons: People shouldn't have to go off-site to help you; and links rot, making the question and its answers useless to people in the future. Please put a [mcve] **in** the question, using Stack Snippets (the `[<>]` toolbar button) to make it runnable. Stack Snippets support React, including JSX; [here's how to do one](http://meta.stackoverflow.com/questions/338537/). – T.J. Crowder Sep 04 '19 at 15:50
  • 1
    @T.J.Crowder Okay thanks for the feedback! – Ezrab_ Sep 04 '19 at 15:55

1 Answers1

3

That code is mostly correct, except:

  1. When modifying state based on existing state, you need to use the callback version of setState, since state updates are asynchronous.

  2. Rather than a timeout, if you need to observe the updated state (you usually don't, because usually all you're doing is re-rendering), use the completion callback, not setTimeout. See the setState documentation.

So:

updateAction = (newAction) => {
  this.setState(({action}) => ({action: [...action, newAction]}));
};

and

removeElement = (id) => {
  this.setState(
    ({action}) => ({action: action.filter((value) => value !== id)}),
    () => {
      console.log(`removeElement function: ${this.state}`);
    }
  );
};

And as pointed out in the comments, you'll get more useful output from your console.log if you do it like this:

() => {
  console.log("removeElement function:", this.state);
}

...since converting this.state to a string will just give you "[object Object]" (unless you've provided a toString method on it).

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875