2

I am learning react. I was trying to understand redux. I developed a simple page which adds a items in shopping bag. Now i am trying to implement removing items.

My goal is to pass an index in REMOVE_ITEM action. I will remove the item with that index in my action. But whenever i click remove Button it gives me the following error.

TypeError: Cannot read property 'index' of undefined

this error is from the line:

onClick={() =>this.props.REMOVE_ITEM({ index: this.props.items[i].index})

I tried to use array.map function first. but inside array.map this.props was outside the variable scope. So i moved the code in a separate function. Then called that function from render. But still my problem was not solved.

I also tried to bind this.props.REMOVE_ITEM in constructor. But i was not successful in doing so.

My entire code is given below.

import React, { Component } from "react";
import { connect } from "react-redux";
class ShopingBag extends Component {
  constructor(props) {
    super(props);
    this.state = {};
  }

  bag_items() {
    var list = [];
    console.log(this.props);
    for (var i = 0; i < this.props.items.length; i++) {
      list.push(
        <tr>
          <td>{this.props.items[i].index}</td>
          <td>{this.props.items[i].name}</td>
          <td>{this.props.items[i].unit}</td>
          <td>
            <button
              onClick={() =>
                this.props.REMOVE_ITEM({
                  index: this.props.items[i].index
                })
              }
            >
              Remove
            </button>
          </td>
        </tr>
      );
    }

    return list;
  }
  render() {
    console.log(this.props);
    return (
      <div>
        Shoping Bag
        <div>
          <table>
            <thead>
              <tr>
                <th>id</th>
                <th>item</th>
                <th>unit</th>
                <th>Action</th>
              </tr>
            </thead>
            <tbody>
              {/* {this.props.items.map(function(item, i) {
                return (
                  <tr key={i}>
                    <td>{item.index}</td>
                    <td>{item.name}</td>
                    <td>{item.unit}</td>
                    <td>
                      <button
                        onClick={() => this.props.REMOVE_ITEM({ index: 0 })}
                      >
                        Remove
                      </button>
                    </td>
                  </tr>
                );
              })} */}
              {this.bag_items()}
              <tr>
                <td />
                <td />
                <td />
                <td>{this.props.total}</td>
              </tr>
            </tbody>
          </table>
        </div>
      </div>
    );
  }
}

const mapDispatchToProps = dispatch => {
  return {
    REMOVE_ITEM: data => dispatch({ type: "REMOVE_ITEM", payload: data })
  };
};

const mapStateToProps = store => {
  return {
    items: store.sR.items,
    total: store.sR.total
  };
};
export default connect(
  mapStateToProps,
  mapDispatchToProps
)(ShopingBag);
ahnafscm
  • 57
  • 1
  • 6
  • The problem you're having actually isn't related to React. :-) `i` when your click handler is run isn't what it is when you *created* your click handler, see the linked question's answers for why. In this specific case, the React way to handle it would be to use `map` to create `list`: `const list = this.props.items.map(item => stuff);` where in `stuff` you use `item` rather than `this.props.items[i]`. You could also add some destructuring: `const list = this.props.items.map(({index, name, unit}) => stuff);` and use `index`, `name`, and ` unit` in `stuff`. – T.J. Crowder Jan 12 '19 at 09:32
  • (To be clear: The `map` replaces your `for` loop.) – T.J. Crowder Jan 12 '19 at 09:33
  • `bag_items` using `item`: https://pastebin.com/CtRwLtHV And using destructuring: https://pastebin.com/NPxL6PjC Happy coding! – T.J. Crowder Jan 12 '19 at 09:36
  • I have tried map function. (if you see my code. then you will find the map function commented out). If i use map function then i cant access the "this.props.REMOVE_ITEM" function. – ahnafscm Jan 12 '19 at 09:53
  • Yes, you can, see the links above. It needs to use an *arrow function* for the `map` callback, though, because otherwise `this` is wrong. (Well, there are other ways, but an arrow function is the modern way.) More [here](http://stackoverflow.com/questions/20279484/how-to-access-the-correct-this-context-inside-a-callback) and [here](https://stackoverflow.com/questions/3127429/how-does-the-this-keyword-work). – T.J. Crowder Jan 12 '19 at 10:01
  • i have used the arrow function as advised in your link in comments above but i still have the problem. this.props.REMOVE_ITEM is not accessible inside the map function. I tried to bind this using the Link provided at the top. But i was not successful in doing so. – ahnafscm Jan 12 '19 at 13:21
  • The linked questions answer your question above about the "TypeError: Cannot read property 'index' of undefined" error, and using an arrow function **definitely** means you're accessing `this.props` correctly. If you have a *further* problem using `mapDispatchToProps` (since apparently `REMOVE_ITEM` doesn't exist on props, I suggest posting a question about that with a [mcve] demonstrating the problem, ideally a **runnable** one using Stack Snippets (the `[<>]` toolbar button). Stack Snippets support React, including JSX; [here's how to do one](http://meta.stackoverflow.com/questions/338537/). – T.J. Crowder Jan 12 '19 at 13:52
  • **Yes, it is** if you use `map` as I showed you in the pastebin links (or as described in the link question's answers). Just repeating that it isn't isn't make it true. Also, there's no update in the question. Just do the MCVE for a new question, using `map` and an arrow function as I showed you, **if** when you do that you still have an issue -- because that means the issue is not the issue listed **here**. – T.J. Crowder Jan 12 '19 at 14:22
  • ("isn't isn't" => "isn't doesn't" above, sorry) – T.J. Crowder Jan 12 '19 at 14:28
  • 1
    i was updating the question after the comment but while updating i found my mistake. i was trying to get this.props.item. Anyways i was successful in invoking REMOVE_ITEM action. Thanks for your help man, – ahnafscm Jan 12 '19 at 14:30
  • Great! Happy coding! – T.J. Crowder Jan 12 '19 at 14:44

0 Answers0