Reputation: 1705
For an example class component like below:
class Todo extends Component {
state = {
list: ["First Todo"],
text: ""
};
handleSubmit(e) {
e.preventDefault();
if (this && this.setState) {
console.log("this present in handleSubmit");
this.setState(prevState => ({
list: prevState.list.concat(this.state.text),
text: ""
}));
} else {
console.log("this not present in handleSubmit");
}
}
handleChange(e) {
if (this && this.setState) {
console.log("this present in handleChange");
this.setState({
text: e.target.value
});
} else {
console.log("this not present in handleChange");
}
}
removeItem(index) {
if (!this || !this.setState) {
console.log("this not present in removeItem");
}
console.log("this present in removeItem");
const list = this.state.list;
list.splice(index, 1);
this.setState({ list });
}
render() {
return (
<div>
<h1>TODO LIST</h1>
<form onSubmit={this.handleSubmit}>
<input value={this.state.text} onChange={e => this.handleChange(e)} />
<button>Add</button>
<ol>
{this.state.list.map((item, index) => {
return (
<li key={index}>
{item}
<button onClick={() => this.removeItem(index)}>Delete</button>
</li>
);
})}
</ol>
</form>
</div>
);
}
}
The behavior of this
binding to the class methods is not consistent.
Playing around with the component we will find that, handleChange
and removeItem
has the correct this
context, whereas handleSubmit
has this
context as undefined
.
Both of the function which has correct this
context is represented as an arrow function in jsx. Like below:
<input value={this.state.text} onChange={e => this.handleChange(e)} />
While the handleSubmit
is passed as function itself. Like below:
<form onSubmit={this.handleSubmit}>
But, I really don't know why this is happening. Because, In my understanding, it should not have mattered how the function was passed i.e. as the function itself or arrow representation as above.
Upvotes: 1
Views: 41
Reputation: 31625
In my understanding, it should not have mattered how the function was passed...
So here is new thing to learn
Passing onChange={e => this.handleChange(e)}
will be the same as using .bind
in the constructor or passing the reference and using .bind
.
When passing it as an arrow function in the render method, it will get the this
of the component instead of the method's this.
You should notice that onChange={e => this.handleChange(e)}
is not a good practice because on every render you will be creating a new function.
Upvotes: 1
Reputation: 21317
Arrow functions have lexical this
. Which means its value is determined by the surrounding scope. So when you use it instead of class methods
the this
value will be maped to the instance. But when you call this.onSubmit
this
will be refering to the local scope and not to the instance itself. To solve it either use arrow functions
or bind
the onSubmit
method in your constructor.
constructor(props){
super(props)
this.onSubmit = this.onSubmit.bind(this)
}
Upvotes: 4