Pass multiple parameters to event handlers in React

So im trying to make react work with ES6 syntax. In ES5 I had setInitialState without a constructor which worked with the function binding syntax. I have a list of prices which is arbitrary and I want the state to change when the input element is changed. But the right price has to be changed.

I'm not even quite sure this is the right way to do it. Can someone please tell me the most recent way this should be done?

Here is my code:

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

export default class PriceTable extends Component {
  constructor(props, context) {
    super(props, context);

    this.state = {
      pid: this.props.pid || "12345",
      name: this.props.name || "name",
      prices: this.props.prices || [
        {count: 1, desc: 'one', price: 8.25},
        {count: 6, desc: 'six', price: 7.60},
        {count: 12, desc: 'twelve', price: 6.953}
      ]
    };

    this.setPid = this.setPid.bind(this);
    this.setName = this.setName.bind(this);
    this.setCount = this.setCount.bind(this, i);
    this.setDesc = this.setDesc.bind(this, i);
    this.setPrice = this.setPrice.bind(this, i);
    this.logDebug = this.logDebug.bind(this);
  }

  setPid(e) {
    this.setState({pid: e.target.value})
  }

  setName(e) {
    this.setState({name: e.target.value})
  }

  setCount(i, e) {
    var newPrices = this.state.prices
    newPrices[i].count = e.target.value
    this.setState({prices: newPrices})
  }

  setDesc(i, e) {
    var newPrices = this.state.prices
    newPrices[i].sec = e.target.value
    this.setState({prices: newPrices})
  }

  setPrice(i, e) {
    var newPrices = this.state.prices
    newPrices[i].price = e.target.value
    this.setState({prices: newPrices})
  }

  _renderPriceRow(price, i) {
    return (
      <tr key={i}>
        <td >
          <input type="text" className="form-control" defaultValue={price.count} onChange={this.setCount(this, i).bind(this, i)}/>
        </td>
        <td >
          <input type="text" className="form-control" defaultValue={price.desc} onChange={this.setDesc(this, i).bind(this, i)}/>
        </td>
        <td >
          <input type="text" className="form-control" defaultValue={price.price} onChange={this.setPrice(this, i).bind(this, i)}/>
        </td>
      </tr>
    );
  }

  render() {
    return (
      <div className="row">
       ...
      </div>
    );
  }
}

And this is the error...

PriceTable.jsx:21 Uncaught ReferenceError: i is not defined
    at new PriceTable (PriceTable.jsx:21)

You are binding the functions incorrectly

In your constructor you need not specify the argument, you only need to bind it like this.setDesc = this.setDesc.bind(this);

Also In your onChange, when you want to pass paramters to the function you specify it with bind and not pass as arguments and bind them again .

onChange={this.setDesc.bind(this, i)}

You entire code will look like

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

export default class PriceTable extends Component {
  constructor(props, context) {
    super(props, context);

    this.state = {
      pid: this.props.pid || "12345",
      name: this.props.name || "name",
      prices: this.props.prices || [
        {count: 1, desc: 'one', price: 8.25},
        {count: 6, desc: 'six', price: 7.60},
        {count: 12, desc: 'twelve', price: 6.953}
      ]
    };

    this.setPid = this.setPid.bind(this);
    this.setName = this.setName.bind(this);
    this.setCount = this.setCount.bind(this);
    this.setDesc = this.setDesc.bind(this);
    this.setPrice = this.setPrice.bind(this);
    this.logDebug = this.logDebug.bind(this);
    this._renderPriceRow = this._renderPriceRow.bind(this);
  }

  setPid(e) {
    this.setState({pid: e.target.value})
  }

  setName(e) {
    this.setState({name: e.target.value})
  }

  setCount(i, e) {
    var newPrices = this.state.prices
    newPrices[i].count = e.target.value
    this.setState({prices: newPrices})
  }

  setDesc(i, e) {
    var newPrices = this.state.prices
    newPrices[i].sec = e.target.value
    this.setState({prices: newPrices})
  }

  setPrice(i, e) {
    var newPrices = this.state.prices
    newPrices[i].price = e.target.value
    this.setState({prices: newPrices})
  }

  _renderPriceRow(price, i) {
    return (
      <tr key={i}>
        <td >
          <input type="text" className="form-control" defaultValue={price.count} onChange={this.setCount.bind(this, i)}/>
        </td>
        <td >
          <input type="text" className="form-control" defaultValue={price.desc} onChange={this.setDesc.bind(this, i)}/>
        </td>
        <td >
          <input type="text" className="form-control" defaultValue={price.price} onChange={this.setPrice.bind(this, i)}/>
        </td>
      </tr>
    );
  }

  render() {
    return (
      <div className="row">
       ...
      </div>
    );
  }
}

You could also make use of Arrow functions to pass parameters like

onChange={(e) => this.setDesc(e,  i)}

Use the onChange method like this:

onChange={this.setCount.bind(this, i)}
onChange={this.setDesc.bind(this, i)}
onChange={this.setPrice.bind(this, i)}

Remove these lines from constructor:

this.setCount = this.setCount.bind(this, i);
this.setDesc = this.setDesc.bind(this, i);
this.setPrice = this.setPrice.bind(this, i);

We can bind the function in constructor, where no extra parameter is required, like the these functions in your case:

this.setPid = this.setPid.bind(this);
this.setName = this.setName.bind(this);
this.logDebug = this.logDebug.bind(this);

But if in any function you want to pass any extra parameter, then you need to use either arrow function or bind that function by using .bind(this, parameter).

Note:

Another thing that you need to change here is, the way you are updating the state values, You should never mutate state variable directly. When you assign an array to any variable, that variable will have the reference of that array, means whatever changes you will do to that variable will affect the original array.

So you need to create a copy of that variable and then do the changes on that and use setState to update the values.

As per DOC:

Never mutate this.state directly, as calling setState() afterwards may replace the mutation you made. Treat this.state as if it were immutable.