TypeError: Cannot read property ‘handleChange’ of undefined

Tags: , ,



I am trying to build a todo list app with React. Getting the error “Cannot read property of handleChange undefined”. Below is the code i am working on. Moreover, todosData is an array of objects having id, text and completed(boolean – true/false) as properties.

    import React from "react";
    import './App.css'; 
    import List from './Components/Todo-Startup/content';
    import todosData from './Components/Todo-Startup/todosData';

    class App extends React.Component {

         constructor(){
            super()
              this.state = {
              todos: todosData
          }
          this.handleChange = this.handleChange.bind(this)
  }

    handleChange(id){
         console.log("Changed", id)
    
  }

    render() {
         const todoComponents = this.state.todos.map(function(task){
             return (
               <List key={task.id} 
                  task={task} 
                  handleChange={this.handleChange} />
      )
    })

  return (
    <div className = "App">
      {todoComponents}
    </div>
  )
 }
 }

   export default App;

The content.js is as follows,

import React from 'react';

const List = function (props){
    return (
        <div className="todo-list">
            <input 
                onChange={function(){props.handleChange(props.task.id)
            }}  
                type="checkbox" 
                checked={props.task.completed}/> 
                <p>{props.task.text}</p>
        </div>

    );
}

export default List;

And finally the array todosData,

    const todosData = [
    {
        id: 1,
        text: "Take out the trash",
        completed: true
    },
    {
        id: 2,
        text: "Grocery Shopping",
        completed: false
    },
    {
        id: 3,
        text: "Get a hair cut",
        completed: true
    },
    {
        id: 4,
        text: "Study & Practice JavaScript",
        completed: true
    }
    
]

export default todosData;

Answer

Because this is function-scoped, except for arrow-functions.

const todoComponents = this.state.todos.map(task => (
    <List key={task.id} 
          task={task} 
          handleChange={this.handleChange} />
))

Alternative, if you have to use function.

const that = this;
const todoComponents = this.state.todos.map(function (task) (
    <List key={task.id} 
          task={task} 
          handleChange={that.handleChange} />
));

See also How to access the correct `this` inside a callback?



Source: stackoverflow