React: How to get the index of clicked element?

Created on 16 Dec 2015  路  9Comments  路  Source: facebook/react

I have some list item, and I want know which one is clicked by user,
so I set onClik on every <li> item,
and I user event.target to get the node clicked,
but I get this issue, my <li> items has children nodes,
when user click the children inside the <li> element,
event.target is not the element I want, how do I fix it?

my code:

var React = require('react');
var ReactDOM = require('react-dom');

var CC = React.createClass({

    handleClick: function(e) {
        console.log(e.target.getAttribute('data-key'));
    },

    render: function() {
        var s = {
            border: '1px solid #ddd',
            display: 'block',
            padding: '10px'
        };
        var items = this.props.arr.map(function(a, i) {
            return (
                <li key={i} onClick={this.handleClick} style={s} data-key={i}>
                    <img src="images/joy.png"/>
                </li>
                );
        }, this);

        return (
            <ul >
                {items}
            </ul>
            );
    }
});


var App = React.createClass({
    getInitialState: function () {
        return {
            arr: [1,2,3]
        };
    },

    render: function() {
        return (
            <div>
                <CC arr={this.state.arr}/>
            </div>
        );
    }
});

ReactDOM.render(<App/>, document.getElementById('app'));

when user click the <img> inside <li>,
e.target.getAttribute('data-key') return null

I do can fix it by add the data-key attribute to all of <li> element's children,
like:

var items = this.props.arr.map(function(a, i) {
    return (
        <li key={i} onClick={this.handleClick} style={s} data-key={i}>
            <img src="images/joy.png" data-key={i} />
        </li>
        );
}, this);

but I don't think it is a elegant way.

Question

Most helpful comment

I have written a jsfiddle to show you how it can be done without using data attributes at all. Basically you bind the index to the handleClick function and it will be passed into it as a parameter when it's called.

https://jsfiddle.net/qmkqd7u6/3/

Also, this is a usage question, rather than a bug in the React core. Usage questions are better answered on sites like StackOverflow, try to use github issues for tracking bugs in the React core.

All 9 comments

I have written a jsfiddle to show you how it can be done without using data attributes at all. Basically you bind the index to the handleClick function and it will be passed into it as a parameter when it's called.

https://jsfiddle.net/qmkqd7u6/3/

Also, this is a usage question, rather than a bug in the React core. Usage questions are better answered on sites like StackOverflow, try to use github issues for tracking bugs in the React core.

Thanks @yangshun!

@yangshun
:joy: No offence,
I just thought that I can get the more official answer of the question.
And we can always add Question label to issues

@yangshun's answer is exactly what any of us would have said for an "official" answer 馃榾

@zpao That's why I prefer Github issue to StackOverflow. :joy:

@littlee Every minute we spend answering usage questions on github is one fewer minutes we can spend fixing React to make it better for everyone. That's why we push people toward StackOverflow, where the answers are generally just as good (sometimes better) and don't consume disproportionate amounts of our time.

handleChange(index, event) {
const {name, value} = event.target;
const list = [].concat(this.state.someArray)
list[index)[name] = value
this.setState({someArray: list})
}

// Use this handler, and don't forget about name
this.state.someArray.map((item, index)=>{
return(
//.... with
onChange={this.handleChange.bind(this, index)}
)
}

I wrote it by mobile, sorry for any typo

@yangshun
Binding a function inside render causes performance issues.

@dryleaf Performance issues are app-specific. It's true that there's impact on performance. You should measure your app's performance before determining there are issues. You could:

  1. Extract out the item into its own component, pass it the callback prop and the item id/index
  2. Create a class method on your item component
  3. Call the callback prop with the specific item id/index from within your item component
Was this page helpful?
0 / 5 - 0 ratings