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

Mur*_*göz 31 javascript reactjs

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

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
  }));
}
Run Code Online (Sandbox Code Playgroud)

如果我删除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,
  }));
}
Run Code Online (Sandbox Code Playgroud)

为什么以上工作但不是我使用时this.setState(prevState=> ...)

Lyu*_*mir 28

这是预期的行为,因为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);
Run Code Online (Sandbox Code Playgroud)
div {
  padding: 50px;
  background: rgba(0,0,0,0.5);
  color: white;
}
Run Code Online (Sandbox Code Playgroud)
<!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>
Run Code Online (Sandbox Code Playgroud)


Mur*_*göz 13

随着@thirtydot的评论我得到了一个有效的解决方案.

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

所以我将其存储event.currentTarget到一个变量并使用它,就像它在ReactJs事件池中所解释的那样

看起来像这样,它的工作原理

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

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


小智 9

要解决此问题 - 在调用表单的 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
}
Run Code Online (Sandbox Code Playgroud)