Synchronous Event Bubbling/Mounting Difference vs React
See original GitHub issue(Moved from https://github.com/developit/preact-compat/issues/418, apologies if this is the wrong place)
Hey there!
First, thank you for the awesome library 👍 , I’ve had a surprisingly painless process converting multiple React apps to Preact. I did, however, run into an issue the other day regarding what I believe to be a difference between event handling and the component lifecycle in React and Preact. Basically:
- In React, components rendered due to an event (i.e. a Modal opening in response to a click event) are mounted after that event bubbles to the document root.
- In Preact (with or without
preact-compat
), the newly-mounted component mounts before that event bubbles, and thus is able to capture it, which can lead to unexpected issues. I noticed this after registering document event listeners on aModal
’scomponentDidMount
, and seeing that it started capturing the click event that caused the modal to open in the first place.
I have provided a demo below for both the Preact and React use case. If you check the console output you should be able to see the difference I’m describing:
// console logs on button click:
1) Example mounted
2) Document noticed a click event
3) Example noticed a document click event
- React Demo (happens in React
^15.4.0
as well).
// console logs on button click:
1) Document noticed a click event
2) Example mounted
For Reference
document.addEventListener('click', () => {
console.log('Document noticed a click event')
})
export class Example extends Component {
componentDidMount () {
console.log('Example mounted!')
// we can fix this by wrapping the addEventListener call in a `setTimeout` to
// let the current call stack complete.
document.addEventListener('click', (e) => {
console.log('Example noticed a document click event')
this.props.onClose()
})
}
render () {
return <h1>Example Thing</h1>
}
}
export default class App extends Component {
state = { show: false }
render () {
return (
<div>
<button onClick={() => this.setState({ show: true })}>Show Thing</button>
{this.state.show && <Example onClose={() => this.setState({ show: false })} />}
</div>
)
}
}
Thanks in advance!
Issue Analytics
- State:
- Created 6 years ago
- Reactions:3
- Comments:10 (5 by maintainers)
Top Results From Across the Web
SyntheticEvent - React
The synthetic events are different from, and do not map directly to, the browser's ... false from an event handler will no longer...
Read more >What's the Difference Between Synthetic React Events and ...
React uses a synthetic event system, which is a cross-browser wrapper around the browser's native event. In most cases, a developer may not...
Read more >Event Bubbling and Event Catching in JavaScript and React
React doesn't attach event handlers to nodes – rather to the root of the document instead. When an event is fired, React calls...
Read more >Test event bubbling in React - Stack Overflow
I have a parent and a child components. Click event is fired somewhere in a Bar component. How to test that doSmth was...
Read more >React lifecycle methods: An approachable tutorial with examples
The constructor method is called before the component is mounted to the DOM. In most cases, you would initialize state and bind event...
Read more >Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start FreeTop Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
Top GitHub Comments
Always fun to revisit issues from almost 2 years back. I’m actually using Preact X in a new project and thus far haven’t encountered the issue.
@developit Yes i suppose that is a caveat with event delegation. I’m out of ideas that maintain sync DOM operations.