Javascript 在React中调用event.persist()后调用event.preventDefault()

Javascript 在React中调用event.persist()后调用event.preventDefault(),javascript,reactjs,performance,dom-events,Javascript,Reactjs,Performance,Dom Events,我曾在React中研究过合成事件,我知道React会汇集事件以提高性能。我还知道React中的事件不是DOM事件。我已经阅读了一些关于这个主题的帖子和帖子,但是在调用event.persist之后,我找不到任何关于调用preventDefault的内容 例如,许多网站都提到,如果我们想要捕获event.target的值,一个选项就是将其缓存以供以后使用,但这不适用于我的用例 我想限制正在侦听onDragOver事件的事件处理程序。为了在React中执行此操作,我必须通过3个函数传递事件,在第一个

我曾在React中研究过合成事件,我知道React会汇集事件以提高性能。我还知道React中的事件不是DOM事件。我已经阅读了一些关于这个主题的帖子和帖子,但是在调用
event.persist
之后,我找不到任何关于调用
preventDefault
的内容

例如,许多网站都提到,如果我们想要捕获
event.target
的值,一个选项就是将其缓存以供以后使用,但这不适用于我的用例

我想限制正在侦听
onDragOver
事件的事件处理程序。为了在React中执行此操作,我必须通过3个函数传递事件,在第一个函数上调用
event.persist
,以便最后一个函数可以看到它

但是,
event.preventDefault
在我调用它时无效。就好像我们一旦调用了
event.persist
,就这样,再也没有回头路了

下面是一些代码,但您可能会发现在上面进行实验更有帮助

import React,{Component}来自'React';
从“油门去盎司”导入{throttle};
从“./DropItem”导入DropItem;
类DropZone扩展组件{
建造师(道具){
超级(道具);
this.onDragOverThrottled=油门(500,this.onDragOver);
this.onDragStart=this.onDragStart.bind(this);
this.handleDragOver=this.handleDragOver.bind(this);
}
onDragStart(e,id){
log('dragstart:',id);
e、 dataTransfer.setData(“id”,id);
}
昂德拉戈弗(e){
e、 preventDefault();//如果event.persist在它之前触发,则此操作不起任何作用
console.log('dragover…');
}
手工艺品(e){
e、 坚持();
这是(e);
}
render(){
const items=this.props.items.map((项目,索引)=>{
返回;
});
返回(
{this.props.onDrop(e,this.props.location)}>
{this.props.title}
{items}
);
}
}
导出默认DropZone;
/*
附注1
这一行中的注释表明节流有效,但preventDefault无效,我们不能将任何框拖放到其他位置。
附注2
这将完全跳过节流,但preventDefault不起作用,允许将长方体移动到其他区域。由于此处禁用了节流功能,onDragOver会多次触发,有时会阻止用户快速移动箱子。
*/
我咨询过的所有来源都有效地实现了去盎司或节流来捕获一个值,然后用该值做一些事情,但是没有一个来源像我尝试的那样在
持久化
之后尝试调用
preventDefault
。其中一些来源如下:

  • 关于节流和去抖的博客
  • 通过以下方式限制输入的示例:
  • A这正是我的目标,但不是用React写的

经过进一步的研究和实验,我发现了如何解决这个问题

TL;DR
我认为
event.persist()
以某种方式阻止了
event.preventDefault()
按预期工作的理论是不正确的

真正的问题
我的拖放应用程序无法使用节流功能的原因是
event.persist()
不会将事件转发给其他处理程序,而只是让其他处理程序可以访问它。这意味着必须对使用事件的每个处理程序调用
event.preventDefault()
。现在我这么说似乎很明显,但因为我必须通过多个处理程序发送事件来实现节流,所以我错误地认为我正在将事件从一个传递到另一个

文档
我上面所说的是我的观察结果,并非来自React的官方文件。但政府确实这样说:

如果希望以异步方式访问事件属性,则 应该对事件调用
event.persist()
,这将删除 池中的合成事件,并允许创建对该事件的引用 由用户代码保留

虽然我以前读过这篇文章,但我忽略了它,因为我没有考虑我所做的是非同步的。但答案仍然在这里——它允许用户代码保留对事件的引用

了解更多信息

对于那些想深入了解这一点的人,请务必查看我在StackBlitz中提供的详细信息。

你不能有重复的道具名称。@Jonaswills,你能详细说明一下吗?我不清楚你指的是什么。
onDragOver={…}onDragOver={…}
不起作用。第二个优先于第一个。其中一个功能甚至不起作用,明白了。也许我不清楚,但在StackBlitz上,你可以切换这些选项,看看一个没有节流的应用程序和一个实现节流但不起作用的应用程序之间的区别。那么。。。没关系,我相信会有不同的事情:您正试图以异步方式在不同的事件循环周期中调用
event.preventDefault()
(因为您使用了节流-这是关于超时的)。如果我们使用
,我们将看到相同的结果(
preventDefault
不会阻止我们离开)在旧的(相当于HTML4语法:)vanilla js中。不把它作为答案,因为我不知道如何以适当的方式修复代码。
import React, { Component } from 'react';
import { throttle } from 'throttle-debounce';
import DropItem from './DropItem';

class DropZone extends Component {
  constructor(props) {
    super(props);
    this.onDragOverThrottled = throttle(500, this.onDragOver);
    this.onDragStart = this.onDragStart.bind(this);
    this.handleDragOver = this.handleDragOver.bind(this);
  }

  onDragStart(e, id) {
    console.log('dragstart: ', id);
    e.dataTransfer.setData("id", id);
  }

  onDragOver(e) {
    e.preventDefault();  // this does nothing if event.persist fires before it
    console.log('dragover...');
  }

  handleDragOver(e) {
    e.persist();
    this.onDragOverThrottled(e);
  }

  render() {
    const items = this.props.items.map((item, index) => {
      return <DropItem item={item} key={index} onDragStart={this.onDragStart} />;
    });

    return (
      <div
        className={this.props.class}
        //onDragOver={this.handleDragOver}  // See note 1 below
        onDragOver={this.onDragOver}  // See note 2 below
        onDrop={(e) => {this.props.onDrop(e, this.props.location)}}>
        <span className="task-header">{this.props.title}</span>
        {items}
      </div>
    );
  }
}

export default DropZone;

/*

NOTE 1
Commenting in this line shows that throttling works but preventDefault does not and we cannot drag and drop any box to another location.

NOTE 2
This skips throttling altogether but preventDefault does work which allows the box to be moved to a different area. Because throttling is disabled here, onDragOver fires a lot and, at times, keeps the user from moving boxes around quickly.

*/