Cannot read property 'onRowClickHandler' of undefined

Viewed 119

I am pretty new to JS and React-Bootstrap and have read a few other questions related to this error. However, I am still unable to solve my problem. Thankful for any help you can give.

I am trying to implement a row that when clicked on will unhide another row beneath it with more detail about that row. I found this onclick handler from another question, but it was written like

onclickHandler = () => {} 

which was giving me babel errors and I can't add that to my package

Here is my code simplified, didn't include the campaign objects, but just assume its a pretty simple json object

class Gateway extends React.Component {

  onRowClickHandler(e){
    const hiddenElement = e.currentTarget.nextSibling;
    hiddenElement.className.indexOf("collapse show") > -1 ? 
    hiddenElement.classList.remove("show") : hiddenElement.classList.add("show");
  }

   render() {
    function renderTable(element, index) {
      return (
        <tbody key={element.campaignId}>
          <tr onClick={() => this.onRowClickHandler()}>
            <td>{element.campaignId}</td>
            <td>{element.contextualSignal.value}</td>
            <td>{element.bid}</td>
            <td>{element.retrievalScore}</td>
          </tr>
          <tr className="collapse">
            <td colSpan="4">
              Demo Content1
            </td>
          </tr>
        </tbody>
      )} // End of renderTable.

    return (
        <Table id="retrievalTable" striped bordered hover variant="dark">
          <thead>
            <tr>
              <th>Campaign ID</th>
              <th>Contextual Signal Value</th>
              <th>Bid</th>
              <th>Retrieval Score</th>
            </tr>
          </thead>
          {this.state.campaigns.map(renderTable)}
        </Table>
      </div>
    )}
}

export default Gateway

When I click on a row I get the error

Uncaught TypeError: Cannot read property 'onRowClickHandler' of undefined
2 Answers

the this reference is not referring to your react class but rather to the renderTable function, if you can move it to the class property and bind it using the react class constructor or to the render function

class Gateway extends React.Component {

onRowClickHandler(e){
    const hiddenElement = e.currentTarget.nextSibling;
    hiddenElement.className.indexOf("collapse show") > -1 ? hiddenElement.classList.remove("show") : hiddenElement.classList.add("show");
  }

renderTable(element, index) {
      return (
        <tbody key={element.campaignId}>
          <tr onClick={() => this.onRowClickHandler()}>
            <td>{element.campaignId}</td>
            <td>{element.contextualSignal.value}</td>
            <td>{element.bid}</td>
            <td>{element.retrievalScore}</td>
          </tr>
          <tr className="collapse">
            <td colSpan="4">
              Demo Content1
            </td>
          </tr>
        </tbody>
      )
    }

render() {

return (
<Table id="retrievalTable" striped bordered hover variant="dark">
          <thead>
            <tr>
              <th>Campaign ID</th>
              <th>Contextual Signal Value</th>
              <th>Bid</th>
              <th>Retrieval Score</th>
            </tr>
          </thead>
          {this.state.campaigns.map((e, i) => this.renderTable.bind(this, e, i))}
        </Table>
      </div>
    )
  }
}

export default Gateway

something like that, don't copy and paste., you probably know the next step

You have to be careful about the meaning of this in JSX callbacks. In JavaScript, class methods are not bound by default. If you forget to bind this.handlerFunction and pass it to onClick, this will be undefined when the function is actually called.

This is not React-specific behavior; it is a part of how functions work in JavaScript. Generally, if you refer to a method without () after it, such as onClick={this.handlerFunction}, you should bind that method.

Handling Events Reference

There are two ways to deal with this, first is to bind the function under constructor like:

constructor(props) { super(props);

// This binding is necessary to make `this` work in the callback
this.onRowClickHandler= this.onRowClickHandler.bind(this);

}

or second is to create an arrow function like:

onRowClickHandler = () => {
  // your logic here
}
Related