开发者问题收集

React setState 函数中使用 e.target.value 的问题

2018-07-10
15530

我在 React 中遇到了一个奇怪的问题。我想我可能还没有完全掌握 React 的工作原理,我非常感谢您的帮助。

请在下面找到我的 React 组件:

class myComponent extends Component {
  state = {
    value: ''
  }

  updateValue = e => {
    this.setState({
      value: e.target.value
    })
  }

  render() {
    return (
     <form>
      <input type="text" onChange={this.updateValue} defaultValue={this.state.value} />
     </form>
    )
  }
}

然后,现在如果我在文本字段中输入一些内容,我将收到以下警告和错误:

警告:出于性能原因,此合成事件被重复使用。如果您看到此信息,则表示您正在访问已发布/无效的合成事件上的属性 target 。它设置为 null。如果您必须保留原始合成事件,请使用 event.persist()。

未捕获的 TypeError:无法读取 null 的属性“value”

但如果我将“updateValue”方法更改为:

updateValue = e => {
    const newValue = e.target.value
    this.setState({
      value: newValue
    })
  }

它将正常工作。

3个回答

更新答案

正如@FelixKling 指出的那样,我的答案并不完全正确。我的答案仅在您将 函数 作为参数传递给 setState 时有效,而如果您像问题中那样传递 对象 则无效。

如果您将 对象 传递给 setState ,则将立即评估该参数,即在事件被取消之前。因此,不会发生上述错误。

如果您将 函数 传递给 setState ,则将在该函数内评估该参数,这发生在 updateValue 完成/返回并且事件被取消之后。如果将函数传递给 setState ,则必须在 setState 之前将 e.target.value 存储在变量中(或调用 e.persist() )。

旧的(稍微错误)答案

出现此问题是因为(如错误消息所示)在回调(您的 updateValue 函数)完成时将事件设置为 null。

因为 this.setState() 是一个异步函数 ,所以它不会立即执行。因此, this.setState() 实际上是在您的 updateValue 完成后执行的,因此是在事件无效之后执行的。

您的解决方案实际上是 React 文档中提出的方法

tskjetne
2018-07-10

The SyntheticEvent is pooled. This means that the SyntheticEvent object will be reused and all properties will be nullified after the event callback has been invoked. This is for performance reasons. As such, you cannot access the event in an asynchronous way.

基本上,由于 React 的事件池,点击事件( e )在异步 setState() 中无法访问,除非您使用 event.persist() (如您收到的警告中所述)。

React 事件池: https://reactjs.org/docs/events.html

joknawe
2018-07-10

如果有人正在寻找方法来实现这一点。这里有一个片段。

class myComponent extends Component {
  constructor(props) {
    super(props);
    this.state = {
      value: ''
    };
    this.updateValue = this.updateValue.bind(this);
  }
  updateValue(e) {
    this.setState({ value: e.target.value })
  }
  render() {
    return ( <form>
      <input type="text" value={this.state.value} 
        onChange={this.updateValue} 
        defaultValue={this.state.value} />
      <h4>Controlled Input:</h4> <p>{this.state.value}</p>
      </form>
    ); 
  }
};
ray
2021-04-08