1.react为什么要提供合成事件?
官方文档的描述:
SyntheticEvent 实例将被传递给你的事件处理函数,它是浏览器的原生事件的跨浏览器包装器。除兼容所有浏览器外,它还拥有和浏览器原生事件相同的接口
可以看出React 想实现一个全浏览器的框架, 为了实现这种目标就需要提供全浏览器一致性的事件系统,以此抹平不同浏览器的差异
2.react的合成事件和原生事件如何对应,如何绑定呢?
合成事件和原生事件的对应关系被存放在EventPlugin
中,可以认为是将不同的合成事件函数封装成一个模块,每个模块只处理自己对应的合成事件,方便解耦
React 在一开始就将事件插件全部加载进来, ReactDOMClientInjection
injectEventPluginsByName({
SimpleEventPlugin: LegacySimpleEventPlugin,
EnterLeaveEventPlugin: LegacyEnterLeaveEventPlugin,
ChangeEventPlugin: LegacyChangeEventPlugin,
SelectEventPlugin: LegacySelectEventPlugin,
BeforeInputEventPlugin: LegacyBeforeInputEventPlugin
});
第一个对象是 registrationNameModule,实现合成事件到plugin的映射,判断一个组件的prop是否是事件类型,如果再才会被当做事件处理
{
onBlur: SimpleEventPlugin,
onClick: SimpleEventPlugin,
onClickCapture: SimpleEventPlugin,
onChange: ChangeEventPlugin,
onChangeCapture: ChangeEventPlugin,
onMouseEnter: EnterLeaveEventPlugin,
onMouseLeave: EnterLeaveEventPlugin,
...
}
第二个对象是 registrationNameDependencies,这个对象是合成事件到原生事件的映射
{
onBlur: ['blur'],
onClick: ['click'],
onClickCapture: ['click'],
onChange: ['blur', 'change', 'click', 'focus', 'input', 'keydown', 'keyup', 'selectionchange'],
onMouseEnter: ['mouseout', 'mouseover'],
onMouseLeave: ['mouseout', 'mouseover'],
...
}
第三个对象是 plugins, 这个对象就是上面注册的所有插件列表
plugins = [LegacySimpleEventPlugin, LegacyEnterLeaveEventPlugin, ...];
1.在React 的协调(Reconciler)阶段,也可以说是diff阶段,标记出哪些 DOM 类型 的节点需要添加或者更新
2.当检测到需要创建一个节点或者更新一个节点时, 使用 registrationNameModule 查看一个 prop 是不是一个事件类型,如果是则执行下一步
3.通过 registrationNameDependencies 检查这个 React 事件依赖了哪些原生事件类型。
4.检查这些一个或多个原生事件类型有没有注册过,如果有则忽略
5.如果这个原生事件类型没有注册过,则注册这个原生事件到 document
上
3.setState是异步还是同步
网上有不少答案是这样说的:在钩子函数和合成事件中是异步,在原生事件和setTimeout中是同步
为什么被setTimeout
包裹的this.setState
可以在当前调用栈获取到更新后的state
?
在老版React
中,事件回调会被包裹在batchedUpdates
函数中执行
function batchedUpdates(fn) {
let prevContext = context;
context |= batchedContext;
try {
fn();
} finally {
context = prevContext;
}
}
被包裹的事件回调fn
通过全局变量context
就能获取当前是否处于batchedContext
的上下文环境。
如果处于该环境就执行一些批处理操作。
而是否用setTimeout
包裹this.setState
影响的,就是在执行this.setState
时全局变量context
是否包含batchedContext
。
在v17以后,就不会出现这样的问题
4. React 17 中事件系统有哪些新特性
将顶层事件绑定在
container
上而不是document
上能够解决我们遇到的多版本共存问题React 17 中终于支持了原生捕获事件的支持, 对齐了浏览器原生标准。同时
onScroll
事件不再进行事件冒泡。onFocus和
onBlur使用原生
focusin,
focusout` 合成。取消事件复用