Gaurav Jagtap
Gaurav Jagtap

Reputation: 151

React.JS Cannot read property within an Array loop

I have the following code.

 var ImageList = React.createClass({
 getComponent: function(index){
      console.log(index);
 },
render: function() {
var results = this.props.data;
return (
  <div className="row">
    {results.map(function(result) {
      return(
              <a className="th medium-3 columns" href="#" onClick=  {this.getComponent.bind(this, 1)}>
                <img alt="Embedded Image" key={result.id} src={"data:" + result.type + ";"  + "base64," + result.image} />
              </a>
      )      
    })}
  </div>
);
}
});

The second return function basically loops an array of images and shows them. I wanted an OnClick event when clicked should trigger the getComponent method. However if the OnClick event is within the array loop it throws the following error:

Uncaught TypeError: Cannot read property 'getComponent' of undefined.

However if i use the same code and just add the onClick even after the looping function like below:

 var ImageList = React.createClass({
 getComponent: function(index){
      console.log(index);
 },
render: function() {
var results = this.props.data;
return (
  <div className="row">
    {results.map(function(result) {
      return(
              <img alt="Embedded Image" key={result.id} src={"data:" + result.type + ";"  + "base64," + result.image} />
      )      
    })}
    <a className="th medium-3 columns" href="#" onClick=  {this.getComponent.bind(this, 1)}>
  </div>
);
}
});

Ends up working fine. But since i need to keep a unique id for each image only then can i complete the remaining function of getComponent the second method isn't much use for me. Hence is there any way to make it work within the Loop?

Upvotes: 1

Views: 2019

Answers (2)

Aleksandras
Aleksandras

Reputation: 595

You can use ES6 arrow functions to automatically preserve this context:

results((result) => { ... })

or just pass this as second param to the map:

results(function(result) { ... }, this)

Upvotes: 0

tonyhb
tonyhb

Reputation: 3796

Your scope changes within the .map method:

{results.map(function(result) {
    // `this` is different inside this anonymous function
})}

What you want to do is either use ES6' fat arrow syntax, which automatically creates an anonymous function with the same scope, or store the current scope of this in a variable:

ES6 Fat Arrow (read more here):

render: function() {
    var results = this.props.data;
    return (
      <div className="row">
        {results.map( (result) => {
            return(
                <a className="th medium-3 columns" href="#" onClick={that.getComponent.bind(that, 1)}>
                    <img alt="Embedded Image" key={result.id} src={"data:" + result.type + ";"  + "base64," + result.image} />
                </a>
            )
        })}
      </div>
    );
    }
});

Note that you'll need a transpiler — such as babel.io — to change this into ES2015 which browsers currently understand to run. This is considered "best practice", as ES6/7 brings better functionality to JS.

Storing a reference to this:

render: function() {
    var results = this.props.data,
        that = this;
    return (
      <div className="row">
        {results.map(function(result) {
            return(
                <a className="th medium-3 columns" href="#" onClick={that.getComponent.bind(that, 1)}>
                    <img alt="Embedded Image" key={result.id} src={"data:" + result.type + ";"  + "base64," + result.image} />
                </a>
            )
        })}
      </div>
    );
    }
});

Upvotes: 1

Related Questions