Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: checkbox with preventDefault on click should not trigger SyntheticEvent #22735

Closed
wants to merge 13 commits into from
23 changes: 21 additions & 2 deletions packages/react-dom-bindings/src/events/DOMPluginEventSystem.js
Original file line number Diff line number Diff line change
Expand Up @@ -259,15 +259,34 @@ function processDispatchQueueItemsInOrder(
}
}

// `registerTwoPhaseEvent` create additional event by dependencies in queue.
// Some dependencies event called `preventDefault` which should not trigger synthetic event.
// In current check logic, we only check `click` to not to trigger `change`.
// Ref:
// https://html.spec.whatwg.org/multipage/input.html#the-input-element
function checkEventValidation(event: ReactSyntheticEvent) {
if (
event.nativeEvent.defaultPrevented &&
event.type === 'change' &&
event.nativeEvent.type === 'click'
) {
return false;
}

return true;
}

export function processDispatchQueue(
dispatchQueue: DispatchQueue,
eventSystemFlags: EventSystemFlags,
): void {
const inCapturePhase = (eventSystemFlags & IS_CAPTURE_PHASE) !== 0;
for (let i = 0; i < dispatchQueue.length; i++) {
const {event, listeners} = dispatchQueue[i];
processDispatchQueueItemsInOrder(event, listeners, inCapturePhase);
// event system doesn't use pooling.
if (checkEventValidation(event)) {
processDispatchQueueItemsInOrder(event, listeners, inCapturePhase);
// event system doesn't use pooling.
}
}
// This would be a good time to rethrow if any of the event handlers threw.
rethrowCaughtError();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,29 @@ describe('ChangeEventPlugin', () => {
expect(called).toBe(2);
});

it('should not fire change for checkbox input when preventDefault is called in onClick', () => {
const handleReactChange = jest.fn();
const handleNativeChange = jest.fn();

const node = ReactDOM.render(
<input
type="checkbox"
defaultChecked={true}
onClick={event => {
event.preventDefault();
}}
onChange={handleReactChange}
/>,
container,
);
node.addEventListener('change', handleNativeChange);

node.click();

expect(handleNativeChange).toHaveBeenCalledTimes(0);
expect(handleReactChange).toHaveBeenCalledTimes(0);
});

it('should not fire change setting the value programmatically', () => {
let called = 0;

Expand Down