简体   繁体   中英

React - this is undefined when binding function to component

I have this code. I imported some components from Semantic UI.

import React from 'react'
import { Card, Image, Grid } from 'semantic-ui-react'

I am trying to call function when error (404) appears when loading image.

export default class HotelCards extends React.Component {
  // constructor
  constructor(props){
    super(props)
    this.handleError = this.handleError.bind(this);
  }
  // state
  state = {}

This is the function I'd like to call: (not that if I log this inside render function I get instance of current class)

  handleError() {
    console.log(this);
  }

  render() {
    if (!this.props.hotels) return null;
    return (
        <Grid doubling stackable columns="4" className="cards-container">
        {
            this.props.hotels.map(function(e, i) {
                return (
                  <Grid.Column key={i} className="card-column">
                    <Card>

From this element:

                      <Image src={e.hotel.image} onError={this.handleError} />
                    </Card>
                  </Grid.Column>
                )
            })
        }
      </Grid>
    );
  }//render
}//class

However I get error that this is undefined .

TypeError: this is undefined
Stack trace:
render/<@http://localhost:1337/app/bundle.js:63883:92
...

In vanilla JavaScript my approach for this would be

<img src="image.png" onError="this.onerror=null;this.src='/placeholder.jpg';" />

How do I bind this function to component properly?

The typical approach is using the so called "late binding", ie

constructor() {
    // ...
    this.handleError = this.handleError.bind(this);
}

handleError() {
    console.log('THIS', this);
}

The reason your code did not work was because your fat arrow is binding to the context in which your class is being defined.

Alternatively, you could also bind at the rendering level as suggested in another answer, so:

<Image src={e.hotel.image} onError={this.handleError.bind(this)} />

However, the problem with that solution is that it produces a new handler function on every call to your render method, which can (but don't have to) negatively influence your rendering performance if you're using some kind of property equality testing optimization techniques.

Fat arrow functions as methods in a class are not supported in ES6, so you'd first have to define handError as method like this:

handleError() {
    console.log('test');
}

and you should be able to bind to it so it can use this if required:

 <Image src={e.hotel.image} onError={this.handleError.bind(this} />

To void the bind in your render function (which in some case can have performance) you can do the binding in your constructor function:

this.handleError = this.handleError.bind(this);

Ok guys, I found the reason why this is undefined .

It is because these stuff happen inside .map method, so I had to bind this to it like this:

this.props.hotels.map(function(e, i) {
 ...
}, this)

or as @apendua commented, by using arrow function so this doesn't get lost:

 this.props.hotels.map((e, i) => {
     ...
  })

@kunok : nice you found your answer. Arrow function ( => ) keep the this context same as enclosing function.

添加this.state是组件内部的构造函数。

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM