-1

Hey I am trying to delete the element I have clicked on

My app.js

export default class App extends Component {
constructor(props) {
    super(props);
    
    this.state = {

        ninja: [
            {
                name: 'Ryu',
                age: 30,
                belt: 'black',
                id: 1
            }, {
                name: 'Jacy',
                age: 34,
                belt: 'yellow',
                id: 2
            }, {
                name: 'Ikenna',
                age: 20,
                belt: 'green',
                id: 3
            }, {
                name: 'Cole',
                age: 50,
                belt: 'red',
                id: 4
            }
        ]

    }

}
    deleteNinja (itemToBeDeleted) {
        console.log(itemToBeDeleted)
    }
    render = () => <div>
        {this
            .state
            .ninja
            .map(function (ninja) {
                return (
                    <div>
                        <div>{ninja.name}</div>
                        <div>{ninja.age}</div>
                        <div>{ninja.belt}</div>
                        <button
                            onClick={this
                            .state
                            .deleteNinja
                            .bind(this)}>Delete</button>
                    </div>
  )

              
            })}

    </div>
}

When I add the function deleteninja to my button it tells me cannot read state of undefined. I read something about binding it and still it wont do it. If I remove the button everything works fine

Emile Bergeron
  • 17,074
  • 5
  • 83
  • 129
Jerry
  • 23
  • 5
  • 1
    You don't need `state.deleteNinja`. `deleteNinja` is part of the component, not the state. Try just `this.deleteNinja()`. – zero298 Sep 21 '20 at 18:32
  • it says that deleteNinja is undefined :S – Jerry Sep 21 '20 at 18:34
  • I don't see how `deleteNinja()` can be undefined, it is literally there just the next line before `render()` in the code posted. Are you sure you have ` – HoldOffHunger Sep 21 '20 at 18:39
  • https://gyazo.com/2b81b2bf14c3e6d3a2a33d22cff76737 – Jerry Sep 21 '20 at 18:42
  • 1
    Oh, I see! Sorry, updated answer... `.map(function (ninja) { ....}, this);`, pass `this`! It's not that deleteNinja is undefined, the error there says that you cannot call deleteNinja ON undefined. – HoldOffHunger Sep 21 '20 at 18:46
  • Does this answer your question? [How to access the correct \`this\` inside a callback?](https://stackoverflow.com/questions/20279484/how-to-access-the-correct-this-inside-a-callback) – Emile Bergeron Sep 21 '20 at 18:53

2 Answers2

1

You need to do three things: 1) Set your onClick() to the right location for the function, 2) Pass the ninja argument to the function, not the this argument, 3) Pass this to your map() function...

<button onClick={(ninja) => this.deleteNinja(ninja)} />

And map should be like this...

.map(function (ninja) {
}, this);
  1. Notice that before you had this.state.deleteNinja.bind(), and I replaced this with (ninja) => this.deleteNinja(ninja).

  2. Notice before you passed this to be deleted, deleteNinja.bind(this). Well, you probably don't want to delete the this app, and you have a ninja var that you're mapping on, and a deleteNinja() function, so, probably ideal to pass the ninja, like so, this.deleteNinja(ninja).

HoldOffHunger
  • 18,769
  • 10
  • 104
  • 133
1

Don't give map a function() {} if you want auto binding, use an arrow function.

Also, onClick wants you to give it a function that it should call later. You are passing it undefined because it will be called as you map. See my answer dealing with the same issue here: Why do I need to wrap setState callback in an anonymous arrow function for it to run after state change?.

onClick={console.log("Hello")} // console.log NOW, call undefined later

// vs

onClick={() => console.log("Hello")} // do nothing NOW, call console.log later

Try the following:

class App extends React.Component {
  constructor(props) {
      super(props);

      this.state = {

          ninja: [
              {
                  name: 'Ryu',
                  age: 30,
                  belt: 'black',
                  id: 1
              }, {
                  name: 'Jacy',
                  age: 34,
                  belt: 'yellow',
                  id: 2
              }, {
                  name: 'Ikenna',
                  age: 20,
                  belt: 'green',
                  id: 3
              }, {
                  name: 'Cole',
                  age: 50,
                  belt: 'red',
                  id: 4
              }
          ]

      }

    }
    deleteNinja (itemToBeDeleted) {
        console.log("Will delete");
        console.log(JSON.stringify(itemToBeDeleted, null, 4));
    }
    render() {
        return (
            <div>
                {this.state.ninja.map(ninja => (
                    <div key={ninja.id}>
                        <div>{ninja.name}</div>
                        <div>{ninja.age}</div>
                        <div>{ninja.belt}</div>
                        <button onClick={() => this.deleteNinja(ninja)}>Delete</button>
                    </div>
                ))}
            </div>
        );
    }
}
ReactDOM.render(<App />, document.getElementById("app"));
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>

<div id="app"></div>
zero298
  • 25,467
  • 10
  • 75
  • 100
  • Thanks I dont really get it I think I have to read some more on this. Before I tried doing what HoldOffHunger said but it just told me undefined when i clicked and not telling me which element was clicked. But this works ill try to understand it better thanks – Jerry Sep 21 '20 at 18:48
  • just to clarify is it a callbackfunction or am i completly lost? – Jerry Sep 21 '20 at 18:51
  • 1
    `onClick` is what will be called whenever an element is clicked. That's why it wants a function reference or a function object or some function. You weren't giving it that, you were giving it `undefined` because you called the function that you were "trying" to pass as you mapped. So yes, it is a callback function in that sense. – zero298 Sep 21 '20 at 18:52
  • Why wont this update the render I checked the data on click it removes the element clicked and keeps the others? https://gyazo.com/394adb15f7fbc7d57e39af7fef58be25 – Jerry Sep 21 '20 at 19:08
  • 1
    @Jerry See: [Why calling react setState method doesn't mutate the state immediately?](https://stackoverflow.com/q/30782948/1218980) – Emile Bergeron Sep 21 '20 at 19:10
  • 1
    Because you don't map `data`, you map `ninja`. You're ending up with `{ninja, data}` instead of just `{ninja}`. Rename `data` to `ninja` for the fastest fix or `setState({ninja: data})`. – zero298 Sep 21 '20 at 19:10
  • figured it out have to refer to ninja: data and it works! – Jerry Sep 21 '20 at 19:11