React事件对象

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了React事件对象相关的知识,希望对你有一定的参考价值。

参考技术A 1 .SyntheticEvent说到底是用来模拟原生事件的,如果我们自己实现一个事件来模拟原生事件.我们需要模拟什么?

1 .dispatchConfig

2 .事件公用属性定义

1 .oEvent.stopImmediatePropagation();//Immediate[ɪˈmi:diət] //当一个元素绑定多个事件处理程序的时候,事件会按照顺序全部执行,如果不想让后面的事件处理程序执行,就在当前事件里加这个方法,就不执行后面的事件处理程序了
2 .oEvent.preventDefault();(在ie低版本中用oEvent.returnValue=true)//阻止事件的默认行为,比如阻止a的href链接。在智能设讲用return false。
2 .eventPhase

3 .bubbles:返回一个布尔值,表示当前事件是否会向DOM树上层元素冒泡
4 .cancel:表示改事件是否能被取消
5 .composed:表示是否可以穿过Shadow DOM和常规DOM之间的元素进行冒泡
6 .deepPath:一个由事件流所经过的DOM节点组成的数组
7 .defaultPrevented:一个布尔值,表示event.preventdefault方法是否取消了事件的默认行为
8 .timeStamp:事件创建的时间戳.

1 .插件对事件做分类,不同类型的事件的属性也不同
2 .主要有以下几种

3 .SyntheticMouseEvent 就是 SyntheticEvent 的一个派生类,由 ReactDOM 实现。鼠标事件

1 .SyntheticEvent 中有 preventDefault,stopPropagation,persist,isPersistent,destructor
2 .preventDefault

2 .stopPropagation:同样调用了原生事件的 stopPropagation 方法。大家可能发现了,此时事件已经冒泡到 Document 对象上了,调用原生事件的 stopPropagation 已经太晚了,这么做的目的是改变原生事件对象中的一些属性的值,保持两个事件属性值的统一。 同样,使用了 event.cancelBubble = true 的方式来兼容 IE
3 .persist:这个现在已经无效了.React 17之后不在使用事件池了

4 .dectructor:销毁事件属性,将事件的属性置为初始值

1 .React之前将所有的事件都绑定到了document,实际上的React是没有层级的,这样破坏了事件的捕获和冒泡机制
2 .实现原理:具体的做法是,inst 是触发事件的 fiber 对象,从这个 fiber 对象开始,一路向上,直到找到 HostComponent,这样就找到了事件传播的整条路径,然后从根节点自上而下触发 captured,之后自下而上触发 bubbled

1 .SytheticEvent本质上是对nativeEvent的一次封装.目的是为了达到与nativeEvent相同甚至更好的体验基础.保留进一步扩展的可能性,最终实现事件的跨平台
2 .SyntheticEvent 采用派生的方式,将事件具体的属性交由 SyntheticEvent 的子类来实现,自己只维护事件必须的字段
3 .为了避免 SyntheticEvent 对象频繁创建,更好的利用内存资源,提高性能,SyntheticEvent 会将事件对象缓存起来,最大缓存个数是 10
4 .

1 .ES6 Class写法中箭头函数可以不用单独的使用bind方式来绑定this,可以自动绑定
2 .useRef.current.addEventListener('click')这样来绑定
3 .尽量避免在React中混用合成事件和原生事件DOM事件.另外用reactEvent.nativeEvent.stopPropagation()来组织冒泡是不行的.阻止React冒泡的行为只能用React合成事件系统中.而且没办法阻止原生事件的冒泡.
4 .相反,原生事件中的阻止冒泡行为,却可以阻止React合成事件的传播
5 .原理:react的合成事件系统仅仅是原生DOM事件系统的一个子集.仅仅实现了DOM level3的事件接口,统一了浏览器的兼容问题

React Flux 实现调度链

【中文标题】React Flux 实现调度链【英文标题】:React Flux implement dispatch chain 【发布时间】:2015-06-29 04:38:50 【问题描述】:

我正在尝试将 React 与 Flux 架构一起使用,但偶然发现了一个我无法处理的限制。 问题如下:

    有一个监听事件的商店。事件具有对象 ID。如果需要,我们需要获取对象并将其选中。 如果商店没有具有此 ID 的对象 - 将对其进行查询。在回调中,我们调度另一个事件来存储,该事件负责选择。 如果商店有对象 - 我想分派选择事件,但我不能因为分派正在进行中。

到目前为止我想出的最佳解决方案是将内部调度包装在 setTimeout(f, 0) 中,但它看起来很吓人。

实际上这个问题很普遍——如果每个新的调度都是基于之前的调度处理结果,我应该如何组织调度链而不使用调度嵌套(不违反当前的 Flux 限制)。

有人有解决此类问题的好方法吗?

var selectItem(item) 
    AppDispatcher.dispatch(
        actionType: AppConstants.ITEM_SELECT,
        item: item
    );


// Item must be requested and selected.
// If it's in store - select it.
// Otherwise fetch and then select it.
SomeStore.dispatchToken = AppDispatcher.register((action) => 
    switch(action.actionType) 
        case AppConstants.ITEM_REQUESTED:
            var item = SomeStore.getItem(action.itemId);
            if (item) 
                // Won't work because can't dispatch in the middle of dispatch
                selectItem(item);
             else 
                // Will work
                $.getJSON(`some/$action.itemId`, (item) => selectItem(item));
            
    
;

【问题讨论】:

【参考方案1】:

如果 ITEM_SELECT 是另一个Store 将要处理的事件:

您正在寻找dispatcher.waitFor(array<string> ids): void,它允许您使用register() 返回的SomeStore.dispatchToken 来强制执行商店处理事件的顺序。

商店,假设我们称之为OtherStore,它将处理ITEM_SELECT 事件,应改为处理ITEM_REQUEST 事件,但首先调用dispatcher.waitFor( [ SomeStore.dispatchToken ] ),然后通过SomeStore 获取任何有趣的结果一个公共方法,比如SomeStore.getItem()

但是从您的示例来看,SomeStore 似乎对其内部状态没有做任何事情 ITEM_REQUEST,所以您只需将以下几行移动到 OtherStore 变化

// OtherStore.js
case AppConstants.ITEM_REQUESTED:
        dispatcher.waitFor( [ SomeStore.dispatchToken ] );// and don't even do this if SomeStore isn't doing anything with ITEM_REQUEST
        var item = SomeStore.getItem(action.itemId);
        if (item) 
            // Don't dispatch an event, let other stores handle this event, if necessary
            OtherStore.doSomethingWith(item);
         else 
            // Will work
            $.getJSON(`some/$action.itemId`, (item) => OtherStore.doSomethingWith(item));
        

同样,如果其他商店需要处理OtherStore.doSomethingWith(item) 的结果,他们也可以处理ITEM_REQUESTED,但在继续之前调用dispatcher.waitFor( [ OtherStore.dispatchToken ] )

【讨论】:

examples 没有显示它,但 SomeStore 实际上处理消息。你的方法很好,我想实际上解决了一个问题,但它一般不能解决问题。如果消息处理期间的 SomeStore 可以调度不同的操作类型,那么使用您的方法,您必须在整个端点存储中携带此逻辑。 我想说的是 SomeStore 不应该在消息处理期间调度不同的操作类型。 Flux 开发人员也这么认为,这就是为什么他们将waitFor 包括在他们的 Dispatcher 实现中可用的少数方法中。 waitFor 确实解决了一般问题。我认为您应该将事件链视为一种反模式,并重新考虑如何处理事件。也许包括您的具体示例的更多细节?【参考方案2】:

那么,在查看您的代码时,您是否在项目上设置了“已选择”属性,以便在您的 UI/组件中检查/选择它?如果是这样,只需将您已经在其中的那部分功能加入即可。

if(item) 
    item.selected = true;
    //we're done now, no need to create another Action at this point, 
    //we have changed the state of our data, now alert the components 
    //via emitChange()

    emitChange();

如果您想跟踪商店中当前选定的项目,只需将 ID 或对象作为私有 var,然后进行类似设置。

var Store = (function()

    var _currentItem = ;
    var _currentItemID = 1;

    function selectItem(item) 

          _currentItem = item;
          _currentItemID = item.id;
          emitChange();
    


    (function() 
         Dispatcher.register(function(action)
               case AppConstants.ITEM_REQUESTED:
                   var item = SomeStore.getItem(action.itemId);
                   if (item) 
                        selectItem(item);
                    else 
                   $.getJSON(`some/$action.itemId`, (item) => 
                        selectItem(item);   
                   
         );
    )();


    return 
         getCurrentlySelectedItem: function() 
              return _currentItem;
         ,
         getCurrentlySelectedItemID: function() 
              return _currentItemID;
         
    

)();

最终,您不必为所有内容创建操作。无论您正在操作的项目是什么,它都应该是某个域实体,并且管理该特定实体的状态是您的商店的工作。拥有其他内部函数通常是必需的,因此只需将 selectItem(item) 设为 Store 的内部函数,这样您就不必创建新的 Action 来访问或使用它。

现在,如果您有跨存储问题,并且另一个存储关心您初始存储中某些数据的某些特定更改,这就是 waitFor(ids) 函数的用武之地。它有效地阻止执行,直到第一个存储被更新,那么对方可以继续执行,保证对方Store的数据处于有效状态。

我希望这有意义并解决您的问题,如果没有,请告诉我,希望我能更好地归零。

【讨论】:

【参考方案3】:

您正在编写自己的调度程序吗? setTimeout(f, 0) 是个好技巧。我在最小通量here 中做同样的事情。那里没什么可怕的。 Javascript 的concurrency model 非常简单。

更强大的通量调度程序实现应该为您处理。

【讨论】:

微通量实现万岁 :) 不是已经没有很多了,但这是我的 captray.github.io/vanilla-flux 关于这个问题,可以在商店内创建新的操作,但听起来您正在尝试在调度程序完成调度之前这样做。但是,在那里看到“选择/选择”这个词听起来像 UI 状态正在蔓延到您的应用程序状态。可能值得重新考虑或重新调整您的操作。很难说没有更多的上下文。 @z5h 不,我试图坚持使用fb implementation。试图在网上搜索解决方案,但发现只有人说调度链真的很糟糕。我不喜欢 setTimeout(f, 0) 的诡计,因为看起来我正在使用解决方法来做同样的事情(我实际上并不认为这很糟糕,但倾向于相信聪明人)。感谢 MDN 链接!看来我真的需要一些基础知识! @captray 您的实现与 fb 的实现非常相似(就功能而言)。关于问题:确切地说,我正在尝试从另一个分派中分派,因为只有第二个分派地点有数据要分派。我将选择存储在 App State 中,因为整个应用程序都有当前选择的概念。也许这真的不是什么好主意。 其实一模一样。我只是包含了一个自定义 JS 事件和一个 Reactor,而不是依赖于 Event Emitter 或其他事件解决方案。同样,如果没有看到代码,很难说。上面的第 1 点说您的商店正在收听一个事件?当 Store 向 Dispatcher 注册时,Store 应该只通过提供给 Dispatcher 的回调函数接收数据负载。您的 Store 是否在监听常规 Dispatcher -> Store -> 组件流之外的其他事件?

以上是关于React事件对象的主要内容,如果未能解决你的问题,请参考以下文章

React事件对象

React事件系统之touch

React的条件渲染和列表渲染

如何从 React 中的事件对象访问自定义属性?

写给进阶玩家的 React 事件系统原理

在 React 中使用 setState 更新对象(solidity 事件过滤器)