2

I am new to React. I am trying to associate an on-click handler to a component rendered in a loop in React, but am getting a prop undefined error. My code is as follows:

import React, { Component } from 'react';
import './ImageGallery.css';

class ImageGallery extends Component {

  constructor(props) {
    super(props);
    this.selectImage = this.selectImage.bind(this);
  }

  selectImage(e){
    console.log(e.target);
  }

  render() {
    return (
      this.props.images.map(function(e, i){
        return <img alt={i} key={i} src={e} className="thumbnail" onClick={this.selectImage}/>
      })
    )
  }
}

export default ImageGallery;

Unfortunately the documentation around lists and keys is not very supportive for my scenario, as it does not also cover events: https://reactjs.org/docs/lists-and-keys.htm

The error message is: Cannot read property 'selectImage' of undefined

raven
  • 419
  • 6
  • 14

3 Answers3

4

Replace your map callback to the following, using arrow function

this.props.images.map((e, i) => {
  return <img alt={i} key={i} src={e} className="thumbnail" onClick={this.selectImage}/>
})

Or save this before return statement

const that = this;
return (
  this.props.images.map(function(e, i){
    return <img alt={i} key={i} src={e} className="thumbnail" onClick={that.selectImage}/>
  })
)

It might be useful for you - how this works in javascript.

The Reason
  • 6,327
  • 3
  • 17
  • 36
  • My understanding is that the `this` keyword is lexically scoped to the immediate outer function. So that makes sense. But I assumed that by binding it to the class declaration (i.e. in the constructor), React would "know" which function to bind `this` to. Thank you for your help – raven Apr 03 '18 at 08:33
1

You can use an arrow function instead of function syntax, that way your this object will refer to the context outside of the function - e.g.

arr.map((e, i) => { /* 'this' refers to your component, not internal scope of the function */ })
Mark
  • 329
  • 1
  • 11
0

You have using this into a map() function while rendering. It changes this this reference.

You can do like below. Notice the variable me

render() {
  let me = this;
  return (
    this.props.images.map(function(e, i){
      return <img alt={i} key={i} src={e} className="thumbnail" onClick={me.selectImage}/>
    })
  )
}
ivp
  • 1,498
  • 2
  • 8
  • 19