user13145130
user13145130

Reputation: 13

React onChange event returns a TypeError: props.handleChange is not a function

I created a simple class method called handleChange with a parameter of id under the class App.

I tried to call this handleChange method from a child function component called TodoItem.

When I clicked on the checkbox, the browser returned a TypeError saying that props.handleChange(props.item.id) is not a function, as shown in the pictures:

props.handleChange is not a function

Can someone explain what is wrong on my codes in TodoItem?

App class component:

import React, { Component } from "react";
import TodoItem from "./TodoItem";
import todosData from "./todosData";

class App extends Component {
  constructor() {
    super();
    this.state = {
      todos: todosData,
    };
    this.handleChange = this.handleChange(this);
  }

  handleChange(id) {
    console.log("changed", id);
  }

  render() {
    const todoItems = this.state.todos.map((item) => (
      <TodoItem key={item.id} item={item} handleChange={this.handleChange} />
    ));

    return <div className="todo-list">{todoItems}</div>;
  }
}

export default App;

TodoItem functional component:

import React from "react";

function TodoItem(props) {
  return (
    <div className="todo-item">
      <input
        type="checkbox"
        checked={props.item.completed}
        onChange={(e) => props.handleChange(props.item.id)}
      />
      <p>{props.item.text}</p>
    </div>
  );
}

export default TodoItem;

Upvotes: 1

Views: 7072

Answers (2)

Edgar Henriquez
Edgar Henriquez

Reputation: 1383

In your constructor you're not properly binding your function

class App extends Component {
  constructor(props) {
    super(props);
    this.state = {
      todos: todosData,
    };
    this.handleChange = this.handleChange.bind(this)//<-- This is right
    //this.handleChange = this.handleChange(this);//<-- This is wrong
}

Upvotes: 0

ilkerkaran
ilkerkaran

Reputation: 4364

You either need to bind handleChange on using or convert it into arrow functions. I prefer arrow functions.

binding;

this.handleChange = this.handleChange.bind(this);

arrow function;

handleChange = (id) => {
    console.log("changed", id);
}

P.S: if you don't change the item in the child component there is no point to pass item into child and pass item.id to props.handleChange since it is accessible in the parent component in the first place.

P.S.2: you actually invoke handleChange instead of binding it in your constructor.

Upvotes: 2

Related Questions