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

时间:2017-02-07 12:21:33

标签: 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
  }));
}

如果我删除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=> ...)时却没有?

7 个答案:

答案 0 :(得分:25)

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

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

引用其中一个React核心开发人员 - Sophie Alpert

  

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

查看官方React存储库中讨论的the source以及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>

答案 1 :(得分:12)

根据@thirtydot的评论,我得到了一个有效的解决方案。

  

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

所以我将event.currentTarget存储到变量中并按照ReactJs Event Pooling

中的解释使用了该变量

看起来像这样并且有效

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

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

答案 2 :(得分:2)

动态填充组件时遇到类似的警告消息,要解决此问题,我只需要用箭头功能包装功能即可。

发件人:

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

收件人:

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

答案 3 :(得分:1)

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

答案 4 :(得分:1)

关于此问题和两种不同的解决方案,都有不错的描述,您可以使用此link

进行检查

答案 5 :(得分:0)

您可以使用此类的咖喱函数来处理它。

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

答案 6 :(得分:0)

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

示例:

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