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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/42089795/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 00:53:38  来源:igfitidea点击:

ReactJS can't set state from an event with event.persist()

javascriptreactjs

提问by Murat Karag?z

I need to set a state field which I get from an event, but it doesn't get set when I pass a function to it. The component and method looks like the following:

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

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

If I remove event.persist()then I get the following error :

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

This synthetic event is reused for performance reasons. If you're seeing this, you're accessing the method currentTargeton a released/nullified synthetic event. This is a no-op function. If you must keep the original synthetic event around, use event.persist(). See https://facebook.github.io/react/docs/events.html#event-poolingfor more information.

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

For some reason the following code works:

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

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

Why does the above works but not when I use this.setState(prevState=> ...)?

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

采纳答案by Lyubomir

That's the expected behaviour, because event.persist()doesn't imply that currentTargetis not being nullified, in fact it should be - that's compliant with browser's native implementation.

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

This means that if you want to access currentTarget in async way, you need to cache it in a variable as you did in your answer.

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



To cite one of the React core developers - Sophie Alpert.

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

currentTarget changes as the event bubbles up – if you had a event handler on the element receiving the event and others on its ancestors, they'd see different values for currentTarget. IIRC nulling it out is consistent with what happens on native events; if not, let me know and we'll reconsider our behavior here.

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

Check out the sourceof the discussion in the official React repository and the following snippet provided by Sophie that I've touched a bit.

查看官方 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>

回答by Murat Karag?z

With the comment from @thirtydot I got a working solution.

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

I think it's because setState is "async", so by the time the function you pass to setState is executed (and the event is accessed), the event is no longer around. In the second version, the event is accessed immediately and its currentTarget passed to setState

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

So I stored the event.currentTargetto a variable and used that as it's explained in the ReactJs Event Pooling

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

Looks like this and it works

看起来像这样并且有效

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

However this does not explain why event.persist()is not working. I'll accept the answer which explains it.

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

回答by Ruchi Wadhwa

To resolve this issue - before calling handleSubmit of form, call event.persist() and then in handleSubmit() definition - write your logic. For e.g.

要解决此问题 - 在调用表单的 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
}

回答by Kunok

I came across similar warning message when filling components dynamically and to solve this I just had to wrap function with arrow function.

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

From:

从:

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

To:

到:

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