1

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?

2 Answers 2

1

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>
    );
    }
});
Sign up to request clarification or add additional context in comments.

4 Comments

I followed the second method. Would that work on all browsers ?
Thanks again i was breaking my head for the past 1 hour on this. :D
@tonyhb in your second example you're not binding, you're just storing the reference to this in the that variable. There are two other options, you can actually use bind(this) for the callback in map(), or even easier you can also pass the context as a second argument to the map() method.
could you look at this question too stackoverflow.com/questions/31636720/…
0

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)

Comments

Your Answer

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.