简体   繁体   English

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

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

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 currentTarget on a released/nullified synthetic event.如果您看到这一点,则表示您正在访问已发布/已取消的合成事件的方法currentTarget This is a no-op function.这是一个空操作函数。 If you must keep the original synthetic event around, use event.persist().如果您必须保留原始合成事件,请使用 event.persist()。 Seehttps://facebook.github.io/react/docs/events.html#event-pooling for more information.有关详细信息,请参阅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=>...)

That's the expected behaviour , because event.persist() doesn't imply that currentTarget is 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. currentTarget 随着事件的冒泡而改变——如果您在接收事件的元素上有一个事件处理程序,而在其祖先上有其他事件处理程序,他们会看到不同的 currentTarget 值。 IIRC nulling it out is consistent with what happens on native events; IIRC 取消它与本地事件发生的情况一致; if not, let me know and we'll reconsider our behavior here.如果没有,请告诉我,我们将重新考虑我们的行为。

Check out the source of 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>

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.我认为这是因为 setState 是“异步的”,所以当你传递给 setState 的函数被执行(并且事件被访问)时,事件已经不存在了。 In the second version, the event is accessed immediately and its currentTarget passed to setState在第二个版本中,立即访问事件并将其 currentTarget 传递给 setState

So I stored the event.currentTarget to a variable and used that as it's explained in theReactJs 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.然而,这并不能解释为什么event.persist()不起作用。 I'll accept the answer which explains it.我会接受解释它的答案。

To resolve this issue - before calling handleSubmit of form, call event.persist() and then in handleSubmit() definition - write your logic.要解决此问题 - 在调用表单的 handleSubmit 之前,调用 event.persist() 然后在 handleSubmit() 定义中 - 编写您的逻辑。 For eg例如

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

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

In your function you should use const event.preventDefault() or event.prevent()在您的函数中,您应该使用 const event.preventDefault()event.prevent()

example:例子:

updateSpecs1 = (event) => { 
    event.preventDefault()

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

There is a nice description about this problem and 2 different solution, you can check with this link关于这个问题有一个很好的描述和 2 个不同的解决方案,您可以查看此链接

You can handle it using curried function like this.您可以像这样使用柯里化函数来处理它。

const persistEvent = (fun: any) => (e: any) => {
e.persist();
fun(e);
};

now you can write your function like现在你可以像这样写你的函数

persistEvent(toggleFilter);

It's going to be something like this:它将是这样的:

const persistEvent = (fun: any) => (e: any) => {
    e.persist();
    fun(e);
    };

const delayedFunctionality = (e) => {
  setTimeout(()=> {
     console.log(e.target.value)
  },500
}

<input onChange={persistEvent(delayedFunctionality)} />

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM