facebook / react

The library for web and native user interfaces.

Home Page:https://react.dev

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Bug: The onChange synthesis event is not propagation when the child node is added through dangerouslySetInnerHTML

iwfan opened this issue · comments

The onChange synthesis event is not propagation when the child node is added through dangerouslySetInnerHTML.

React version: v17.0.2

Link to code example:

https://codesandbox.io/s/restless-rain-otyzx?file=/src/App.js

Steps To Reproduce

  1. click the radio input element
  2. see logging in console

The current behavior

  1. ✅ onClick event is propagation
  2. ❌ onChange event is not propagation

The expected behavior

  1. onClick event is propagation
  2. onChange event is propagation

@iwfan You added onChange event listener (onChange={handleSyntheticChangeEvent}) to the <div> element.
Read more about change event: https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/change_event.

The change event is fired for <input>, <select>, and <textarea>.

I don't think it works for divs.

Hi @cyntler, I know that change event are triggered for <input>, <select>, and <textarea>, but the change event can be propagated through bubbles.

<div 
  onChange={handleSyntheticChangeEvent} // It's not working!

As you can see, if I add a change event on react element, the change event can no longer bubble.

useEffect(() => {
  containerRef.current.addEventListener("change", handleNativeChangeEvent);
}, [containerRef]);

If I add the change event through native javascript way(addEventListener), the change event can bubble normally.

But if I add the click event whatever through onClick synthesis event or addEventListener, the click event can always bubbles.

And why does the change synthesis event not bubble when the child are added through dangerouslySetInnerHTML?
Why the change event have different bubbles behavior between clicking event?

I have looked into react source code and found out the reason.

Here is the key code

} else if (shouldUseClickEvent(targetNode)) {
getTargetInstFunc = getTargetInstForClickEvent;
}
if (getTargetInstFunc) {
const inst = getTargetInstFunc(domEventName, targetInst);
if (inst) {
createAndAccumulateChangeEvent(
dispatchQueue,
inst,
nativeEvent,
nativeEventTarget,
);

The overall logic is like this.

  1. when the click event is triggered, the nearest React Node (targetNode) to the node that triggered the event is found
  2. determine if the targetNode is an input radio orcheckbox element, and if so, compare the values before and after to see if they have changed, and if so, derive the onChange event

But if the element that triggers the click event is rendered by dangerouslySetInnerHTML element, as in the example above, the latest React Node node div will be found, then the shouldUseClickEvent(targetNode) returns false, making it impossible to synthesize the onChange event.

@gaearon Is this a bug or is it intentional, if it is a bug I'm happy to raise a PR to fix it

This issue has been automatically marked as stale. If this issue is still affecting you, please leave any comment (for example, "bump"), and we'll keep it open. We are sorry that we haven't been able to prioritize it yet. If you have any new additional information, please include it with your comment!

Closing this issue after a prolonged period of inactivity. If this issue is still present in the latest release, please create a new issue with up-to-date information. Thank you!