rakibtg rakibtg - 15 days ago 5
Javascript Question

onClick event can't find function in react mapped object

While looping over an object using

map()
React can't find its own classes property!

Here is the class of the component,

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

export default class VideoLists extends Component {

constructor() {
super();
}

getDefaultLists() {
return [
{
title: 'Iridescent (Official Video) - Linkin Park',
url: 'https://www.youtube.com/watch?v=xLYiIBCN9ec',
id: 'xLYiIBCN9ec'
},
{
title: 'Ed Sheeran - I\'m A Mess (x Acoustic Sessions)',
url: 'https://www.youtube.com/watch?v=-t2CR9qZRj0',
id: '-t2CR9qZRj0'
},
{
title: 'Ed Sheeran - Lego House [Official Video]',
url: 'https://www.youtube.com/watch?v=c4BLVznuWnU',
id: 'c4BLVznuWnU'
}
]
}

itemSelected(itemObject) {
console.log(itemObject);
}

render() {
return (
<div>
<div className='panel panel-default'>
<div className='panel-heading'>

<ul className='list-group'>
{this.getDefaultLists().map(function(item, index){
return <li
key = { index }
className='list-group-item'
onClick={ this.itemSelected.bind(this) }>
{ item.title } <br/>
<small className='listurl'>{ item.url }</small>
</li>;
})}
</ul>

</div>
</div>
</div>
);
}

}


When a user would click on an item it should call the function called itemSelected and also binding the current
this
element with this.

But when the application is throughing and error.

Here is the error message:


Uncaught TypeError: Cannot read property 'itemSelected' of undefined(…)


How I can call this function in this case from the loop?

Answer

you are losing the this context because of your map function. not only do you need to bind that, to get the data object sent though you need to actually tell it to do that. like this.

<ul className='list-group'>
    {this.getDefaultLists().map( (item, index) => {
        return (
            <li key ={index} className='list-group-item' onClick={() => this.itemSelected(item)}>
                { item.title }
                <br/>
                <small className='listurl'>{ item.url }</small>
            </li>
         ); 
    })}
</ul>

you can try shadowing your this context, shouldn't be necessary, but worth a shot.

const self = this;
...
<ul className='list-group'>
    {self.getDefaultLists().map( (item, index) => {
        return (
            <li key ={index} className='list-group-item' onClick={() => self.itemSelected(item)}>
                { item.title }
                <br/>
                <small className='listurl'>{ item.url }</small>
            </li>
         ); 
    })}
</ul>
Comments