Brian Bier Brian Bier - 3 months ago 7
Javascript Question

REACT React how to access the correct "this" after a callback

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>
)
}
}

Answer

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:

  1. Binding the method to an object, with .bind()
  2. Not passing 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

Comments