0

In the below code snippet, I have to pass the method 'handleChange' to another component 'TodoList'. I have tried binding the method, but it didn't solve the problem.

import React from "react";
import TodoList from "./TodoItem";
import "./TodoStyles.css";
import {list} from "./TodoList"

class TodoApp extends React.Component   {
    constructor(){
        super();
        this.state = {
            todos : list
        }

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

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

    render(){

        const todoArr = this.state.todos.map(
            function(i){
                return <TodoList key = {i.id} arr = {i} handleChange = {this.handleChange}/>
            }
        );

        return( 
            <div className = 'todo-list'>
                {todoArr}
            </div>
        )
    }
    
}

export default TodoApp

But using an arrow function instead of a regular function,it solves the issue.

const todoArr = this.state.todos.map(
            (i) => {
                return <TodoList key = {i.id} arr = {i} handleChange = {this.handleChange}/>
            }
        );

Error Message

My question is, can we pass the function "handleChange" to other component using the regular function?

I am working in ES6 and react for the past 1 week, I have tried to search for a solution online, but didn't get any that can solve my problem. So, please be gentle.

saien
  • 5
  • 4

2 Answers2

1

Array.prototype.map() takes a second argument to set what this refers to in the mapping function, so pass this as the second argument to preserve the current context. [*]

You can try this:

const todoArr = this.state.todos.map(
    function(i){
       return <TodoList key = {i.id} arr = {i} handleChange = {this.handleChange}/>
    }, this
);

[*] https://stackoverflow.com/a/30148997/1927991

codemonkey
  • 7,325
  • 5
  • 22
  • 36
1

I am not sure why you cannot use arrow functions. They have been supported in all browsers for years - and tools like Babel (which you can easily configure bundlers like Webpack to use) can convert your code to ES5 automatically if you really have to support something like IE.

However, if you really can't, you can just use the old "lexical this" trick that arrow functions were designed as a substitute for:

    const self = this;
    const todoArr = this.state.todos.map(
        function(i){
            return <TodoList key = {i.id} arr = {i} handleChange = {self.handleChange}/>
        }
    );

Note that this.handleChange = this.handleChange.bind(this) in the constructor doesn't directly help here. (Although you do still need it with the above code to make it work.) It's usually used so you can pass this.handleChange as an event handler and have it use the correct this - here, the function inside map already uses its own this so putting this.handleChange in the event handler won't refer to the correct thing, even if you bind.

Robin Zigmond
  • 17,805
  • 2
  • 23
  • 34
  • Thanks @Robin. It solved the problem. Actually, I read many opinions online and was also advised to avoid arrow functions as much as possible, so I was going for the alternative. – saien Mar 09 '21 at 19:26