Skip to content

Commit 195d5bb

Browse files
authored
Execute event handlers in the context of the instance that it's associated with (#29876)
That way we get owner stacks (native or otherwise) for `console.error` or `console.warn` inside of them. Since the `reportError` is also called within this context, we also get them for errors thrown within event listeners. You'll also be able to observe this in in the `error` event. Similar to how `onUncaughtError` is in the scope of the instance that errored - even though `onUncaughtError` doesn't kick in for event listeners. Chrome (from console.createTask): <img width="306" alt="Screenshot 2024-06-12 at 2 08 19 PM" src="https://github.com/facebook/react/assets/63648/34cd9d57-0df4-44df-a470-e89a5dd1b07d"> <img width="302" alt="Screenshot 2024-06-12 at 2 03 32 PM" src="https://github.com/facebook/react/assets/63648/678117b1-e03a-47d4-9989-8350212c8135"> Firefox (from React DevTools): <img width="493" alt="Screenshot 2024-06-12 at 2 05 01 PM" src="https://github.com/facebook/react/assets/63648/94ca224d-354a-4ec8-a886-5740bcb418e5"> (This is the parent stack since React DevTools doesn't just yet print owner stack.) (Firefox doesn't print the component stack for uncaught since we don't add component stacks for "error" events from React DevTools - just console.error. Perhaps an oversight.) If we didn't have the synthetic event system this would kind of just work natively in Chrome because we have this task active when we attach the event listeners to the DOM node and async stacks just follow along that way. In fact, if you attach a manual listener in useEffect you get this same effect. It's just because we use event delegation that this doesn't work. However, if we did get rid of the synthetic event system we'd likely still want to add a wrapper on the DOM node to set our internal current owner so that the non-native part of the system still can observe the active instance. That wouldn't work with manually attached listeners though.
1 parent 50e89ec commit 195d5bb

File tree

2 files changed

+43
-4
lines changed

2 files changed

+43
-4
lines changed

packages/react-dom-bindings/src/events/DOMPluginEventSystem.js

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ import {
5252
enableLegacyFBSupport,
5353
enableCreateEventHandleAPI,
5454
enableScopeAPI,
55+
enableOwnerStacks,
5556
} from 'shared/ReactFeatureFlags';
5657
import {createEventListenerWrapperWithPriority} from './ReactDOMEventListener';
5758
import {
@@ -70,6 +71,8 @@ import * as FormActionEventPlugin from './plugins/FormActionEventPlugin';
7071

7172
import reportGlobalError from 'shared/reportGlobalError';
7273

74+
import {runWithFiberInDEV} from 'react-reconciler/src/ReactCurrentFiber';
75+
7376
type DispatchListener = {
7477
instance: null | Fiber,
7578
listener: Function,
@@ -255,7 +258,17 @@ function processDispatchQueueItemsInOrder(
255258
if (instance !== previousInstance && event.isPropagationStopped()) {
256259
return;
257260
}
258-
executeDispatch(event, listener, currentTarget);
261+
if (__DEV__ && enableOwnerStacks && instance !== null) {
262+
runWithFiberInDEV(
263+
instance,
264+
executeDispatch,
265+
event,
266+
listener,
267+
currentTarget,
268+
);
269+
} else {
270+
executeDispatch(event, listener, currentTarget);
271+
}
259272
previousInstance = instance;
260273
}
261274
} else {
@@ -264,7 +277,17 @@ function processDispatchQueueItemsInOrder(
264277
if (instance !== previousInstance && event.isPropagationStopped()) {
265278
return;
266279
}
267-
executeDispatch(event, listener, currentTarget);
280+
if (__DEV__ && enableOwnerStacks && instance !== null) {
281+
runWithFiberInDEV(
282+
instance,
283+
executeDispatch,
284+
event,
285+
listener,
286+
currentTarget,
287+
);
288+
} else {
289+
executeDispatch(event, listener, currentTarget);
290+
}
268291
previousInstance = instance;
269292
}
270293
}

packages/react-native-renderer/src/legacy-events/EventPluginUtils.js

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@
77

88
import isArray from 'shared/isArray';
99

10+
import {enableOwnerStacks} from 'shared/ReactFeatureFlags';
11+
12+
import {runWithFiberInDEV} from 'react-reconciler/src/ReactCurrentFiber';
13+
1014
let hasError = false;
1115
let caughtError = null;
1216

@@ -93,10 +97,22 @@ export function executeDispatchesInOrder(event) {
9397
break;
9498
}
9599
// Listeners and Instances are two parallel arrays that are always in sync.
96-
executeDispatch(event, dispatchListeners[i], dispatchInstances[i]);
100+
const listener = dispatchListeners[i];
101+
const instance = dispatchInstances[i];
102+
if (__DEV__ && enableOwnerStacks && instance !== null) {
103+
runWithFiberInDEV(instance, executeDispatch, event, listener, instance);
104+
} else {
105+
executeDispatch(event, listener, instance);
106+
}
97107
}
98108
} else if (dispatchListeners) {
99-
executeDispatch(event, dispatchListeners, dispatchInstances);
109+
const listener = dispatchListeners;
110+
const instance = dispatchInstances;
111+
if (__DEV__ && enableOwnerStacks && instance !== null) {
112+
runWithFiberInDEV(instance, executeDispatch, event, listener, instance);
113+
} else {
114+
executeDispatch(event, listener, instance);
115+
}
100116
}
101117
event._dispatchListeners = null;
102118
event._dispatchInstances = null;

0 commit comments

Comments
 (0)