Passing Arguments to Event Handlers in ReactJS

Following the advice under Thinking In React

I’ve built out my UI first, and just starting to add the functionality. I’ve got the handleClick to hardcode changing the state. But now I want to pass in either the id or the value attribute from each button. You can see what I’ve tried and it’s been commented out. Basically, it’s telling me the id or the value are undefined but am I not declaring those on the line right above it?

Passing 6 out of 16, for the Calculator at FreeCodeCamp.com

repo
live demo, be sure to use the NavBar to get to Calculator
use the hamburger menu on the top left and select JavaScript Calculator to run the test suite, they say it’s designed for Chrome and may encounter bugs in other browsers.

Calculator.js

import React, { Component } from 'react';
// import PropTypes from 'prop-types';
import { Button, Container, Row, Col } from 'react-bootstrap';
import './Calculator.css';

export class Calculator extends Component {
  constructor(props) {
    super(props);
    // Initial State
    this.state = {
      display: 0,
    };

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

  // static propTypes = {
  //   quote: PropTypes.string.isRequired,
  // };

  // handleClick(id) { this.setState(state => ({ display: {id} })); }
  handleClick() { this.setState(state => ({ display: 7 })); }

  render() {
    return (
      <Container id="calculator">
        <Row className="justify-content-center">
          <Col as={Button}
            className="key-pad" xs={2} sm={2} md={1} lg={1}
            id="seven"
            value="7"
            onClick={this.handleClick}
            // onClick={this.handleClick.bind(this, id)}
            // onClick={this.handleClick.bind(this, value)}
            variant="success"
          >
            <h2>
              7
            </h2>
          </Col>
         </Row>
      </Container>
    );
  }
}

export default Calculator;

As already pointed out I am new to React.

I used the reactjs.org getting started example to test out your problem. Sometime it helps to extract the issue into something simpler (‘wood for the trees’ and all that)

Defining the id inside the render function, outside of the returned JSX works.

e.g.

const { Component, createElement } = React

class LikeButton extends Component {

  state = { liked: false }

  handler = (...args) => {
    console.log(this) // likeButton
    console.dir(args) // [0: 'like-button', 1: syntheticBaseEvent]

    return this.setState({ liked: true })
  }

  render () {
    if (this.state.liked) {
      return 'You liked this.'
    }

    // id defined here
    const id = 'like-button'

    return (
      <button
        id = {id}
        onClick = {this.handler.bind(this, id)}
      >
        Like
      </button>
    )
  }
}

const domContainer = document.querySelector('#like_button_container')
ReactDOM.render(createElement(LikeButton), domContainer)

I suspect this isn’t the best approach though.

Thanks for trying to help me figure that out, just for future reference and ongoing documentation this is what end up working for me. I end up getting some feedback on the FCC forum.

          <Col as={Button}
            className="key-pad" xs={2} sm={2} md={1} lg={1}
            id="seven"
            value="7"
            onClick={() => this.handleClick("7")}
            variant="success"
          >
            <h2>
              7
            </h2>
          </Col>

The click handler should actually get passed the event by default, so couldn’t you just get the ID from the event target? I.e. with onClick={this.handleClick}:

handleClick (event) { 
  this.setState(state => ({ display: event.target.id })) 
}

Just saying, but this would achieve the same, with the second argument the handler receives being the event object

onClick = {this.handler.bind(this, 7)}

or

onClick={(event) => this.handleClick("7", event)}

As m3g4p0p points out though, you can access the data from the event object’s target property

You would also be able to access the value as well

handleClick (event) { 
  this.setState(state => ({ 
    display: event.target.id,
    value: event.target.value
  })) 
}