Reputation: 523
I have the react component below. Why this is not defined when changeNameTwo is called?
See jsbin: http://jsbin.com/nuhedateru/edit?js,output
Then why it works in a typical ES6 Class? See jsbin: http://jsbin.com/kiyijuqiha/edit?js,output
class HelloWorldComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
name : 'yolo'
}
}
changeName = () => {
this.setState({name: 'another yolo'});
}
changeNameTwo() {
this.setState({name: 'another yolo'});
}
render() {
return (
<div>
<h1>Hello {this.props.name}</h1>
<p>Name: {this.state.name}</p>
<button onClick={this.changeName}>Change Name</button>
<button onClick={this.changeNameTwo}>Change Name 2</button>
</div>
);
}
}
React.render(
<HelloWorldComponent name="ES2015/ES6"/>,
document.getElementById('react_example')
);
Upvotes: 0
Views: 298
Reputation: 6078
When you use extend Component
instead of React.createClass
you lose autobinding feature. Binding to this
is not a class itself, it’s undefined
. It’s default JavaScript behavior and is quite expected.
Function.prototype.bind()
.export default class CartItem extends React.Component {
render() {
<button onClick={this.increaseQty.bind(this)} className="button success">+</button>
}
}
export default class CartItem extends React.Component {
constructor(props) {
super(props);
this.increaseQty = this.increaseQty.bind(this);
}
render() {
<button onClick={this.increaseQty} className="button success">+</button>
}
}
Consider using this method over Method 1. Every time you use bind it actually creates a copy of a function. So it's much better to use it once in constructor
then every time when your component calls render
method
export default class CartItem extends React.Component {
constructor(props) {
super(props);
this.increaseQty = () => this.increaseQty();
}
render() {
<button onClick={this.increaseQty} className="button success">+</button>
}
}
export default class CartItem extends React.Component {
increaseQty = () => this.increaseQty();
render() {
<button onClick={this.increaseQty} className="button success">+</button>
}
}
Class properties are not yet part of current JavaScript standard. But your are free to use them in Babel using corresponding experimental flag (stage 0 in our case).
You can see original article here
Upvotes: 2
Reputation: 66355
One is a DOM event, the other you are directly calling. By default the context of a click event is the element that was clicked.
It is often desirable to reference the element on which the event handler was fired, such as when using a generic handler for a set of similar elements.
When attaching a handler function to an element using addEventListener(), the value of this inside the handler is a reference to the element. It is the same as the value of the currentTarget property of the event argument that is passed to the handler. (MDN - https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener)
Your methods have a default context of the instance, but only if the context is not specified (a normal function call as opposed to a .call
or .apply
. Thus animal.speak()
will by default have the correct context.
When a function is called as a method of an object, its
this
is set to the object the method is called on. (MDN - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this)
To summarise, the click event sets a specific context which overrides that. As you probably know you can solve it with .call/.bind/.apply or onClick={(e) => this.changeName(e)}
. Probably an implementation today wouldn't do that, but I imagine they have to keep it for compatibilities' sake.
Upvotes: 3