繁体   English   中英

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

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

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

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=>...)

这是预期的行为,因为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
}

在您的函数中,您应该使用 const event.preventDefault()event.prevent()

例子:

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

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

从:

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

到:

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

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

您可以像这样使用柯里化函数来处理它。

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

现在你可以像这样写你的函数

persistEvent(toggleFilter);

它将是这样的:

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