Tom
Tom

Reputation: 2661

passing an event to a child component in React

I'm new to React and this is a very noob question, but I don't understand why this is not working.

I'm trying to build a simple todo List.

My TodoList.js Component looks like this:

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

    export default class TodoList extends Component{
      constructor(props){
        super(props);
        this.state = {
          todos:[
            {
              title:"todo1"
            },
            {
              title:"todo3"
            },
            {
              title:"todo2"
            }
          ]
        }

      }

      handleRemove(idx){
        alert('works');
      }

      render(){
        var todos = this.state.todos.map(function(t,idx){
          return(<TodoItem
                    remove={this.handleRemove.bind(this,idx)}
                    title={t.title}
          />)
        })

        return (
          <div>
            <h1>To do</h1>
          <div>{todos}</div>
          </div>
        )
      }
    }

My child Component looks like this:

import React, {Component} from 'react';

    export default class TodoItem extends Component{
      render(){
        return (
          <div>{this.props.title}
            <button onClick={this.props.remove}>X</button>
          </div>
        )
      }
    }

But I get a TypeError with "Cannot read property 'handleRemove' of undefined". I'm wondering why inside the map function {this} is undefined?

I tried to put this this.handleRemove = this.handleRemove.bind(this) into the constructor.

Didn't change anything. Shouldn't this also be defined inside the .map() ?

Upvotes: 2

Views: 2423

Answers (1)

Alex Harris
Alex Harris

Reputation: 6392

You need to put this as the second argument

If a thisArg parameter is provided to map, it will be used as callback's this value. Otherwise, the value undefined will be used as its this value. The this value ultimately observable by callback is determined according to the usual rules for determining the this seen by a function.

on map:

render(){
        var todos = this.state.todos.map(function(t,idx){
          return(<TodoItem
                    remove={this.handleRemove.bind(this,idx)}
                    title={t.title}
          />)
        }, this)

        return (
          <div>
            <h1>To do</h1>
          <div>{todos}</div>
          </div>
        )
      }
    }

Alternatively, you can use an ES6 arrow function to automatically preserve the current this context:

var todos = this.state.todos.map((t,idx) => {
  return(<TodoItem
    remove={this.handleRemove.bind(this,idx)}
    title={t.title}
  />)
})

Upvotes: 2

Related Questions