Reputation: 111
I recently started learning React and after attaching a callback to a child element I lost the reference of "this" in the parent element. I am building a simple task and when it is checked. I send it back to the parent so that the parent can delete it and reassign the state to the new array without the element. However, I dont have access to this.state.todosTask. I get undefined. Below is my code.
Parent Element TodoList
constructor(props){
super(props);
this.state ={
todosTask: props.todos
}
}
handleCheckedTask(task){
console.log("Now Im in the todost"+task)
this.state.todosTask //= Undefined
}
render(){
return(
<div>
<h4>Todo List</h4>
<div className="form-check">
<label className="form-check-label">
{this.state.todosTask.map((todoElement)=>{
return <Todo todo={todoElement} key={todoElement.id} onCheckedTask={this.handleCheckedTask}/>
})}
</label>
</div>
</div>
)
}
Child Component
completed(event){
let self = this
let task = self.props.todo.task
let id = self.props.todo.id
console.log(self.refs.complete)
this.props.onCheckedTask({id:id,task:task})
}
render(){
return(
<div>
<input
className="form-check-input"
type="checkbox"
ref="complete"
onChange={this.completed.bind(this)}/>
{this.props.todo.task}
</div>
)
}
}
Upvotes: 0
Views: 240
Reputation: 1913
You need to bind the handleCheckedTask
in the constructor to this.
Explanation: In javascript functions and methods are not bound to the containing object as in other languages, like in Java. In javascript this
is dynamic, and it (mostly) means "the caller of the function". For most of the cases, it doesn't make a difference, as normally we call the method through the containing object, as in console.log("foo")
. But sometimes, we want to pass the function as a callback, in this case, the caller is not the object where it was defined, but the one that is using the callback. Fortunately we have 2 ways to fix this problem:
.bind()
this
to the function and get it from the lexical context. (i.e. Using an arrow function)..
constructor(props){
super(props);
this.state = {
todosTask: props.todos
};
this.handleCheckedTask = this.handleCheckedTask.bind(this);
}
Alternatively you can define your handler using a property initializer.
handleCheckedTask = (task) => {
console.log("Now Im in the todost"+task)
this.state.todosTask //= Undefined
}
You can check the details here
Edit: I removed the part where I said that the caller of the callback was the object that was calling it. Normally for callbacks, this
is undefined for normal functions (not arrow functions). For arrow functions this
is recovered from the closure, that is, from the lexical context where it was defined.
Upvotes: 1
Reputation: 21836
ES6 does not have automatic this binding. So, this should be bound manually in the constructor.
constructor(props){
super(props);
this.state = {
todosTask: props.todos
};
this.handleCheckedTask = this.handleCheckedTask.bind(this);
}
Upvotes: 1