Reputation: 55
I'm in the process of learning React. I'm going through a tutorial series that uses ES5. I'm trying to write my components in ES6, which seemed like a straightforward enough process when I was looking at React's documentation about it.
This is the code that is giving me problems:
import React from 'react';
import Button from './button';
import ListItem from './list-item';
export default class DropDown extends React.Component {
constructor() {
super();
this.state = {open: false};
}
handleClick() {
this.state.open = true;
}
render() {
var list = this.props.items.map((item) => {
return <ListItem item={item}/>
});
return (
<div className="dropdown">
<Button onClick={this.handleClick} className='btn-default' title={this.props.title}
subTitleClassName='caret'/>
<ul className={'dropdown-menu ' + (this.state.open ? "show" : "") }>
{list}
</ul>
</div>
)
}
}
I get a TypeError: Cannot read property 'state' of undefined
at
handleClick() {
this.state.open = true;
}
whenever I click the button in Chrome.
Could anyone tell me why this
is undefined, or what I'm doing wrong?
I should probably mention that I'm using Babelify to transpile it to ES5 as part of my gulp/browserify build process.
Upvotes: 0
Views: 3017
Reputation: 36
As it was mentioned in the accepted answer, the problem is in binding function to component instance. However, the easiest approach with arrow function isn't always considered the best practice due to creating a new function for Button's prop on every render (that might be sensitive in some optimisation approaches). So you may use binding-in-constructor approach instead:
class Foo extends Component {
constructor(props) {
super(props);
this.methodName = this.methodName.bind(this);
}
methodName(e) {
// handle click
}
render() {
return <Button onClick={this.methodName} />;
}
}
This way you keep render method, which is called by react pretty often, cleaner from build-up code.
Upvotes: 1
Reputation: 797
The reason why you are getting this error is because 'this' is not autobound for us in es6, as it is in es5 createClass. We can use bind to fix this problem or we can use an arrow function. In your button element, try the following:
<Button
onClick={(e) => this.handleClick(e)}
className='btn-default'
title={this.props.title}
subTitleClassName='caret'
/>
Upvotes: 1