How to get a clicked element in React?

Coming from jQuery, getting a clicked element was a breeze, but I'm having some issues with it in React. Basically, I've got a list, and I want to get a clicked list item (or its index) and animate it.

class TodoApp extends React.Component {
  constructor(props) 
  {
    super(props)
    this.list_element = React.createRef()
    this.state = 
    {
        items: [
        { text: "Learn JavaScript", done: false },
        { text: "Learn React", done: false },
        { text: "Play around in JSFiddle", done: true },
        { text: "Build something awesome", done: true }
      ]
    }
  }
 get_index ()
 {
     console.log(this.list_element.current.children)
 }
  render() {
    return (

        <ol ref={this.list_element}>
        {this.state.items.map(item => (
          <li onClick={ () => this.get_index()}>
              <span>{item.text}</span>
          </li>
        ))}
        </ol>
    )
  }
}

ReactDOM.render(<TodoApp />, document.querySelector("#app"))

Live demo: https://jsfiddle.net/uo1L03ng/

However, I don't know how to get the clicked element in React. Should I use componentDidMount() instead and use the plain JavaScript to get the clicked element and future DOM manipulation?

What would be the best method?


Solution 1:

You can pass in parameters to the onClick handler when mapping over your items array. Array.prototype.map() also gives you access to the index of the element, hence, you can pass it to your doSomething() method.

Here is a CodeSandbox to try it live!

class TodoApp extends React.Component {
  constructor(props) {
    super(props)
    this.list_element = React.createRef()
    this.state = {
      items: [
        { text: 'Learn JavaScript', done: false },
        { text: 'Learn React', done: false },
        { text: 'Play around in JSFiddle', done: true },
        { text: 'Build something awesome', done: true }
      ]
    }
  }

  doSomething(item, index) {
    console.log(item)
    console.log(index)
  }

  render() {
    return (
      <ol>
        {this.state.items.map((item, index) => (
          <li key={item.text} onClick={() => this.doSomething(item, index)}>
            <span>{item.text}</span>
          </li>
        ))}
      </ol>
    )
  }
}

ReactDOM.render(<TodoApp />, document.querySelector('#app'))

Solution 2:

You can pass item as parameter in your onClick function. And you should have key prop for <li> tag, if not, you'll get Warning: Each child in a list should have a unique "key" prop. And use e.currentTarget to interact with DOM element.

get_index(e, item) {
  console.log(e.currentTarget); // <li>
  console.log(item);
}
render() {
  return (
    <ol>
      {this.state.items.map((item, index) => (
        <li key={index} onClick={e => this.get_index(e, item)}>
          <span>{item.text}</span>
        </li>
      ))}
    </ol>
  );
}