简体   繁体   中英

unable to bind event while passing component props to parent component in React

I have this code(pasted below), where I'm trying to bind the 'id' to onChange event to pass it to parent component.

Problem: onChange={this.props.markComplete.bind(this, id)} returns error: TypeError: Cannot read property 'bind' of undefined

while if I replace this.props.markComplete.bind(this, id) to this.markComplete.bind(this, id) , there is no error. I am kind of lost where I am doing wrong.

Note: Other than the 'bind', the passing props is working as expected.

Code:


export class Tasks extends Component {
  getStyle = () => {
    return {
      textDecoration: this.props.todo.completed ? "line-through" : "none"
    };
  };

  render() {
    const { id, title } = this.props.todo;
    return (
      <div style={this.getStyle()}>
        <input
          type="checkbox"
          name="task"
          checked={this.props.todo.completed ? true : null}
          onChange={this.props.markComplete.bind(this, id)}
        />
        <label>{title}</label>
      </div>
    );
  }
}

export default Tasks;

You may simply call markComplete passed through props without .bind -ing:

 const { Component } = React, { render } = ReactDOM, rootNode = document.getElementById('root') const taskList = [ {id:0, title: 'Do something', completed: false}, {id:1, title: 'Do something else', completed: false}, {id:2, title: 'Do some other stuff', completed: true}, ] class Task extends Component { render() { const { id, title, completed } = this.props; return ( <div style={{backgroundColor:this.props.completed ? 'green' : 'none'}}> <input type="checkbox" name="task" checked={completed} onChange={() => this.props.markComplete(id)} /> <label>{title}</label> </div> ); } } class TaskBoard extends Component { constructor(props){ super(props) this.state = {tasks:this.props.tasks} this.handleComplete = this.handleComplete.bind(this) } handleComplete(taskId, completed){ const tasks = [...this.state.tasks], completedTask = tasks.find(({id}) => id == taskId) completedTask.completed = true this.setState({tasks}) } render(){ return( this.state.tasks.map(task => <Task {...{key:task.id, markComplete:this.handleComplete,...task}} />) ) } } render(<TaskBoard tasks={taskList} />, rootNode)
 <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.12.0/umd/react.production.min.js"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.11.0/umd/react-dom.production.min.js"></script><div id="root"></div>

You can't bind the function in this place.

As I can understand from your code, you have another Component and you're passing the markComplete function as props to Tasks Component, right?

You probably have something like this:

export class AnotherComponent extends Component {
  markComplete(id) {
    // doSomething
  }

  render() {
    <Tasks todo={someTodoObject} markComplete={this.markComplete} />
  }
}

You need to bind the markComplete function in this parent Component (or use arrow function), eg:

export class AnotherComponent extends Component {
  // Example using bind
  constructor(props) {
    super(props)

    this.markComplete = this.markComplete.bind(this)
  }

  markComplete(id) {
    // doSomething
  }

  render() {
    <Tasks todo={someTodoObject} markComplete={this.markComplete} />
  }
}

or

export class AnotherComponent extends Component {
  // Example using arrow function
  markComplete = (id) => {
    // doSomething
  }

  render() {
    <Tasks todo={someTodoObject} markComplete={this.markComplete} />
  }
}

This way you bind the function to the Component where your state is.

Also, on the Tasks Component (let's say you're not using .bind there anymore), in your case, you can't use the onChange like that:

onChange={this.props.markComplete(this, id)}

This will call the markComplete function as soon as it is rendered.

If you have a function that needs to be executed after some event (click, change, etc) and this function receives a parameter, you always need to do something like:

onChange={() => this.props.markComplete.bind(this, id)}

So you create a function that will call your function. Otherwise you are already calling the function.

Hope I was clear about it! It's kinda confusing

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM