ReactJS 无法使用 event.persist() 从事件设置状态

IT技术 javascript reactjs
2021-04-22 17:25:17

我需要设置一个从事件中获取的状态字段,但是当我将函数传递给它时它没有设置。组件和方法如下所示:

constructor(props: SomeProps, context: any) {
  super(props, context);
  this.state = {
    isFiltering: props.isFiltering,
    anchor: "",
  };
}

private toggleFilter = (event: any) => {
  event.persist()
  this.setState(prevState => ({
    isFiltering: !prevState.isFiltering,
    anchor: event.currentTarget // does not work, it's null
  }));
}

如果我删除event.persist()然后我收到以下错误:

出于性能原因重用此合成事件。如果您看到这一点,则表示您正在访问已currentTarget发布/无效的合成事件上的方法这是一个无操作功能。如果您必须保留原始合成事件,请使用 event.persist()。有关更多信息,请参阅https://facebook.github.io/react/docs/events.html#event-pooling

出于某种原因,以下代码有效:

private toggleFilter = (event: any) => {
  this.setState({anchor:event.currentTarget}) // works fine
  this.setState(prevState => ({
    isFiltering: !prevState.isFiltering,
  }));
}

为什么上述有效,但当我使用时无效this.setState(prevState=> ...)

6个回答

这是预期的行为,因为event.persist()并不意味着这currentTarget不会被取消,实际上它应该是 - 这符合浏览器的本机实现。

这意味着如果您想以异步方式访问 currentTarget,则需要像在答案中一样将其缓存在变量中。


引用 React 核心开发人员之一 - Sophie Alpert

currentTarget 随着事件的冒泡而改变——如果你在接收事件的元素上有一个事件处理程序,而在其祖先上有其他的事件处理程序,他们会看到 currentTarget 的不同值。IIRC 将其取消与本地事件发生的情况一致;如果没有,请告诉我,我们将在此重新考虑我们的行为。

查看官方 React 存储库中讨论的来源以及 Sophie 提供的以下我接触过的片段。

var savedEvent;
var savedTarget;

divb.addEventListener('click', function(e) {
  savedEvent = e;
  savedTarget = e.currentTarget;
  setTimeout(function() {
    console.log('b: currentTarget is now ' + e.currentTarget);
  }, 0);
}, false);

diva.addEventListener('click', function(e) {
  console.log('same event object? ' + (e === savedEvent));
  console.log('same target? ' + (savedTarget === e.currentTarget));
  setTimeout(function() {
    console.log('a: currentTarget is now ' + e.currentTarget);
  }, 0);
}, false);
div {
  padding: 50px;
  background: rgba(0,0,0,0.5);
  color: white;
}
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>JS Bin</title>
</head>
<body>

  <div id="diva"><div id="divb"> Click me and see output! </div></div>
  
</body>
</html>

通过@thirtydot 的评论,我得到了一个可行的解决方案。

我认为这是因为 setState 是“异步的”,所以当你传递给 setState 的函数被执行(并且事件被访问)时,事件不再存在。在第二个版本中,立即访问事件并将其 currentTarget 传递给 setState

所以我将它存储event.currentTarget到一个变量中,并按照ReactJs 事件池中的说明使用它

看起来像这样并且有效

private toggleFilter = (event: any) => {
        let target = event.currentTarget;   
        this.setState((prevState) => ({
            isFiltering: !prevState.isFiltering,
            anchor: target
        }));
    }

但是,这并不能解释为什么event.persist()不起作用。我会接受解释它的答案。

要解决此问题 - 在调用表单的 handleSubmit 之前,调用 event.persist() 然后在 handleSubmit() 定义中 - 编写您的逻辑。例如

<form id="add_exp_form" onSubmit={(event) => {event.persist();this.handleSubmit(event)}}>

handleSubmit(event){
    // use event.currentTarget - It will be visible here
}

我在动态填充组件时遇到了类似的警告消息,为了解决这个问题,我只需要用箭头函数包装函数。

从:

{ text: "Delete item", onClick: deleteItem },

到:

{ text: "Delete item", onClick: (id) => deleteItem(id) },

关于这个问题和 2 个不同的解决方案有一个很好的描述,你可以查看这个链接

感谢您指出此链接。在设置状态之前,我选择了“缓存值”的解决方案,通过 event.persist() : Just do const value = event.target.value; setState(value)
2021-06-19 17:25:17