在React中向事件处理程序传递多个参数

6

我试图让React与ES6语法配合使用。在ES5中,我没有构造函数而是使用函数绑定语法并设置了setInitialState,这可以正常工作。我有一个价格列表,其中价格是任意的,当输入元素改变时我希望状态(state)也发生变化。但必须改变正确的价格。

我甚至不确定这是否是正确的做法。请有人告诉我应该如何实现最新的方式?

以下是我的代码:

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>
    );
  }
}

这是错误信息...

PriceTable.jsx:21 Uncaught ReferenceError: i is not defined
    at new PriceTable (PriceTable.jsx:21)
2个回答

14

你绑定函数的方式不正确

在构造函数中,你不需要指定参数,只需要像这样绑定它:this.setDesc = this.setDesc.bind(this);

另外,在你的onChange函数中,当你想要向函数传递参数时,应该使用bind而不是直接传递参数并再次绑定。

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

你的整个代码将会是这样:

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>
    );
  }
}

您还可以使用箭头函数来传递参数,如下:

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

这实际上与根本不绑定函数具有相同的效果。我收到以下错误:Uncaught TypeError: Cannot read property 'setCount' of undefined at _renderPriceRow - Dennis Ich
那是因为你还没有绑定renderPriceRow函数。请检查更新。 - Shubham Khatri
请简要解释一下为什么我也必须绑定那个函数?是因为该函数超出了实际类的范围吗?这里似乎有一些奇怪的样板代码。为什么它不像 ES5 之前那样被绑定呢? - Dennis Ich
你需要绑定那个函数,因为它使用 this 作为引用来调用 setCount 函数,如果你不绑定它,函数内的 this 将指向函数本身的上下文。这与绑定其他使用 setState 的函数类似。 - Shubham Khatri

2

使用onChange方法,如下所示:

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

请从constructor中删除这些行:

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

我们可以在构造函数中绑定函数,这里不需要额外的参数,就像您的情况中这些函数一样:bind函数。
this.setPid = this.setPid.bind(this);
this.setName = this.setName.bind(this);
this.logDebug = this.logDebug.bind(this);

但如果您想在任何function中传递任何额外的参数,则需要使用箭头函数bind,通过使用.bind(this, parameter)来将该function绑定。 注意
您需要改变的另一件事是您更新state值的方式,您不应直接突变状态变量。当您将一个array分配给任何变量时,该变量将具有该array的引用,这意味着您对该变量所做的任何更改都会影响原始的array
因此,您需要创建该变量的副本,然后在该副本上进行更改,并使用setState来更新值。
根据文档

永远不要直接突变this.state,因为之后调用setState()可能会替换您所做的突变。将this.state视为不可变的。


好的,我会复制这些内容。实际上,您建议删除的那些行是我尝试修复以前错误的天真方法:Uncaught TypeError: Cannot read property 'setCount' of undefined at _renderPriceRow - Dennis Ich
不,那不是正确的方法,我建议的方法肯定能正常工作,我有把握,会提供可行的代码 :) - Mayank Shukla
因为您没有绑定_renderPriceRow函数。 - Mayank Shukla
请在构造函数中写入以下代码:this._renderPriceRow = this._renderPriceRow.bind(this); - Mayank Shukla

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接