广州海外建站,wordpress 数据库名贵,长春火车站是哪个站,自定义wordpress首页标题一#xff0c;时间机制
是什么
React基于浏览器的事件机制自身实现了一套事件机制#xff0c;包括事件注册、事件的合成、事件冒泡、事件派发等
在React中这套事件机制被称之为合成事件
合成事件#xff08;SyntheticEvent#xff09;
合成事件是 React模拟原生 DOM事…一时间机制
是什么
React基于浏览器的事件机制自身实现了一套事件机制包括事件注册、事件的合成、事件冒泡、事件派发等
在React中这套事件机制被称之为合成事件
合成事件SyntheticEvent
合成事件是 React模拟原生 DOM事件所有能力的一个事件对象即浏览器原生事件的跨浏览器包装器
根据 W3C规范来定义合成事件兼容所有浏览器拥有与浏览器原生事件相同的接口例如
const button button onClick{handleClick}按钮/button如果想要获得原生DOM事件可以通过e.nativeEvent属性获取
const handleClick (e) console.log(e.nativeEvent);;
const button button onClick{handleClick}按钮/button从上面可以看到React事件和原生事件也非常的相似但也有一定的区别
事件名称命名方式不同
// 原生事件绑定方式
button onclickhandleClick()按钮命名/button// React 合成事件绑定方式
const button button onClick{handleClick}按钮命名/button事件处理函数书写不同
// 原生事件 事件处理函数写法
button onclickhandleClick()按钮命名/button// React 合成事件 事件处理函数写法
const button button onClick{handleClick}按钮命名/button虽然onclick看似绑定到DOM元素上但实际并不会把事件代理函数直接绑定到真实的节点上而是把所有的事件绑定到结构的最外层使用一个统一的事件去监听
这个事件监听器上维持了一个映射来保存所有组件内部的事件监听和处理函数。当组件挂载或卸载时只是在这个统一的事件监听器上插入或删除一些对象
当事件发生时首先被这个统一的事件监听器处理然后在映射里找到真正的事件处理函数并调用。这样做简化了事件处理和回收机制效率也有很大提升
执行顺序
关于React合成事件与原生事件执行顺序可以看看下面一个例子
import React from react;
class App extends React.Component{constructor(props) {super(props);this.parentRef React.createRef();this.childRef React.createRef();}componentDidMount() {console.log(React componentDidMount);this.parentRef.current?.addEventListener(click, () {console.log(原生事件父元素 DOM 事件监听);});this.childRef.current?.addEventListener(click, () {console.log(原生事件子元素 DOM 事件监听);});document.addEventListener(click, (e) {console.log(原生事件document DOM 事件监听);});}parentClickFun () {console.log(React 事件父元素事件监听);};childClickFun () {console.log(React 事件子元素事件监听);};render() {return (div ref{this.parentRef} onClick{this.parentClickFun}div ref{this.childRef} onClick{this.childClickFun}分析事件执行顺序/div/div);}
}
export default App;输出顺序为
原生事件子元素 DOM 事件监听
原生事件父元素 DOM 事件监听
React 事件子元素事件监听
React 事件父元素事件监听
原生事件document DOM 事件监听 可以得出以下结论
React 所有事件都挂载在 document 对象上当真实 DOM 元素触发事件会冒泡到 document 对象后再处理 React 事件所以会先执行原生事件然后处理 React 事件最后真正执行 document 上挂载的事件
所以想要阻止不同时间段的冒泡行为对应使用不同的方法对应如下 阻止合成事件间的冒泡用e.stopPropagation() 阻止合成事件与最外层 document 上的事件间的冒泡用e.nativeEvent.stopImmediatePropagation() 阻止合成事件与除最外层document上的原生事件上的冒泡通过判断e.target来避免
document.body.addEventListener(click, e { if (e.target e.target.matches(div.code)) { return; } this.setState({ active: false, }); });
}总结
React事件机制总结如下
React 上注册的事件最终会绑定在document这个 DOM 上而不是 React 组件对应的 DOM(减少内存开销就是因为所有的事件都绑定在 document 上其他节点没有绑定事件)React 自身实现了一套事件冒泡机制所以这也就是为什么我们 event.stopPropagation()无效的原因。React 通过队列的形式从触发的组件向父组件回溯然后调用他们 JSX 中定义的 callbackReact 有一套自己的合成事件 SyntheticEvent
二事件绑定
是什么
在react应用中事件名都是用小驼峰格式进行书写例如onclick要改写成onClick
最简单的事件绑定如下
class ShowAlert extends React.Component {showAlert() {console.log(Hi);}render() {return button onClick{this.showAlert}show/button;}
}从上面可以看到事件绑定的方法需要使用{}包住
上述的代码看似没有问题但是当将处理函数输出代码换成console.log(this)的时候点击按钮则会发现控制台输出undefined
如何绑定
为了解决上面正确输出this的问题常见的绑定方式有如下
render方法中使用bindrender方法中使用箭头函数constructor中bind定义阶段使用箭头函数绑定
render方法中使用bind
如果使用一个类组件在其中给某个组件/元素一个onClick属性它现在并会自定绑定其this到当前组件解决这个问题的方法是在事件函数后使用.bind(this)将this绑定到当前组件中
class App extends React.Component {handleClick() {console.log(this , this);}render() {return (div onClick{this.handleClick.bind(this)}test/div)}
}这种方式在组件每次render渲染的时候都会重新进行bind的操作影响性能
render方法中使用箭头函数
通过ES6的上下文来将this的指向绑定给当前组件同样再每一次render的时候都会生成新的方法影响性能
class App extends React.Component {handleClick() {console.log(this , this);}render() {return (div onClick{e this.handleClick(e)}test/div)}
}constructor中bind
在constructor中预先bind当前组件可以避免在render操作中重复绑定
class App extends React.Component {constructor(props) {super(props);this.handleClick this.handleClick.bind(this);}handleClick() {console.log(this , this);}render() {return (div onClick{this.handleClick}test/div)}
}定义阶段使用箭头函数绑定
跟上述方式三一样能够避免在render操作中重复绑定实现也非常的简单如下
class App extends React.Component {constructor(props) {super(props);}handleClick () {console.log(this , this);}render() {return (div onClick{this.handleClick}test/div)}
}区别
上述四种方法的方式区别主要如下
编写方面方式一、方式二写法简单方式三的编写过于冗杂性能方面方式一和方式二在每次组件render的时候都会生成新的方法实例性能问题欠缺。若该函数作为属性值传给子组件的时候都会导致额外的渲染。而方式三、方式四只会生成一个方法实例
综合上述方式四是最优的事件绑定方式