Brian
Brian

Reputation: 111

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

Upvotes: 0

Views: 240

Answers (2)

Manolo Santos
Manolo Santos

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:

  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

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

vijayst
vijayst

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

Related Questions