Explanation of React Bubble and Prevent Bubble Application
- 2021-08-06 20:37:14
- OfStack
There are three kinds of events to prevent bubbling:
1: Prevent composite events from bubbling to events on the outermost document, using e. nativeEvent. stopImmediatePropagation ();
2: Compose bubbles between events, using e. stopPropagation ();
3: Prevent composite events from bubbling to other native events on document, which need to be judged by e. target. The example code is as follows.
import React,{ Component } from 'react';
import ReactDOM,{findDOMNode} from 'react-dom';
class Counter extends Component{
constructor(props){
super(props);
this.state = {
count:0,
}
}
handleClick(e){
this.setState({count:++this.state.count});
}
render(){
return(
<div ref="test">
<p>{this.state.count}</p>
<a ref="update" onClick={(e)=>this.handleClick(e)}> Update </a>
</div>
)
}
componentDidMount() {
document.body.addEventListener('click',e=>{
// Pass e.target Judge to prevent bubbling
if(e.target&&e.target.matches('a')){
return;
}
console.log('body');
})
}
}
var div1 = document.getElementById('content');
ReactDOM.render(<Counter/>,div1,()=>{});
Demand
Recently, when writing the project of react, I need to write a custom menu by hand, which is different from menu of antd. After clicking the Level 1 menu, I need to pop up a similar Drawer to show Level 2 and Level 3 menus, and the menu style is customized, all of which are displayed in an Drawer.
Difficulties
The difficulty lies in the fact that Drawer pops up when clicking the level 1 menu, and dom and Drawer except Drawer and level 1 menu items are put away.
Problem
At first glance, I think it is to add a click event monitor to document, and add bubbling prevention to Drawer and level 1 menu. This is true, and it is found in the later implementation:
In order to improve performance, react has its own set of event handling mechanism, which is equivalent to handling events globally, that is to say, the listening function is not bound to Dom. Therefore, if the event that prevents react bubbles e. stopPropagation (), it will not bubble the native event, which shows that clicking Drawer will also fold Drawer;; If the native event bubbling e. nativeEvent. stopPropagation () is disabled, the listening function of React cannot be called, which shows that if you click dom other than Drawer, Drawer will not be put away. These are not what we want.
Solutions
The correct gesture should be to determine whether the event. target object is the target object or contains or contains the target object, so as to decide whether to trigger the event
componentDidMount() {
document.addEventListener('click', this.hideDrawer);
}
componentWillUnmount() {
document.removeEventListener('click', this.hideDrawer);
}
hideDrawer = e => {
const { closeDrawer } = this.props;
// Find something that doesn't need to be closed dom 1 Level menu
const tabContent = document.querySelectorAll('.ant-menu-submenu-vertical');
// Find something that doesn't need to be closed dom Drawer
const drawerContent = document.querySelector('#menuDrawer');
// Determine the currently clicked dom Object is contained in the target dom Medium
const isHave = Array.from(tabContent).some(item => item.contains(e.target));
// Close if not included Drawer Include other business logic
if (tabContent !== null && !(isHave || drawerContent.contains(e.target))) {
closeDrawer();
}
};