Skip to content

Commit 9ff60ff

Browse files
authored
[react-events] Fix Scope listener issue (#16658)
1 parent 7126a37 commit 9ff60ff

File tree

4 files changed

+87
-25
lines changed

4 files changed

+87
-25
lines changed

packages/react-reconciler/src/ReactFiberCommitWork.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1343,7 +1343,7 @@ function commitWork(current: Fiber | null, finishedWork: Fiber): void {
13431343
const prevListeners = oldProps.listeners;
13441344
const nextListeners = newProps.listeners;
13451345
if (prevListeners !== nextListeners) {
1346-
updateEventListeners(nextListeners, finishedWork);
1346+
updateEventListeners(nextListeners, finishedWork, null);
13471347
}
13481348
}
13491349
}
@@ -1400,7 +1400,7 @@ function commitWork(current: Fiber | null, finishedWork: Fiber): void {
14001400
const prevListeners = oldProps.listeners;
14011401
const nextListeners = newProps.listeners;
14021402
if (prevListeners !== nextListeners) {
1403-
updateEventListeners(nextListeners, finishedWork);
1403+
updateEventListeners(nextListeners, finishedWork, null);
14041404
}
14051405
}
14061406
}

packages/react-reconciler/src/ReactFiberCompleteWork.js

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -724,7 +724,11 @@ function completeWork(
724724
if (enableFlareAPI) {
725725
const listeners = newProps.listeners;
726726
if (listeners != null) {
727-
updateEventListeners(listeners, workInProgress);
727+
updateEventListeners(
728+
listeners,
729+
workInProgress,
730+
rootContainerInstance,
731+
);
728732
}
729733
}
730734
} else {
@@ -744,7 +748,11 @@ function completeWork(
744748
if (enableFlareAPI) {
745749
const listeners = newProps.listeners;
746750
if (listeners != null) {
747-
updateEventListeners(listeners, workInProgress);
751+
updateEventListeners(
752+
listeners,
753+
workInProgress,
754+
rootContainerInstance,
755+
);
748756
}
749757
}
750758

@@ -1233,7 +1241,12 @@ function completeWork(
12331241
if (enableFlareAPI) {
12341242
const listeners = newProps.listeners;
12351243
if (listeners != null) {
1236-
updateEventListeners(listeners, workInProgress);
1244+
const rootContainerInstance = getRootHostContainer();
1245+
updateEventListeners(
1246+
listeners,
1247+
workInProgress,
1248+
rootContainerInstance,
1249+
);
12371250
}
12381251
}
12391252
if (workInProgress.ref !== null) {

packages/react-reconciler/src/ReactFiberEvents.js

Lines changed: 44 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*/
99

1010
import type {Fiber} from './ReactFiber';
11-
import type {Instance} from './ReactFiberHostConfig';
11+
import type {Container, Instance} from './ReactFiberHostConfig';
1212
import type {
1313
ReactEventResponder,
1414
ReactEventResponderInstance,
@@ -53,6 +53,7 @@ function mountEventResponder(
5353
ReactEventResponder<any, any>,
5454
ReactEventResponderInstance<any, any>,
5555
>,
56+
rootContainerInstance: null | Container,
5657
) {
5758
let responderState = emptyObject;
5859
const getInitialState = responder.getInitialState;
@@ -65,25 +66,28 @@ function mountEventResponder(
6566
responderState,
6667
fiber,
6768
);
68-
let instance = null;
69-
let node = fiber;
70-
while (node !== null) {
71-
const tag = node.tag;
72-
if (tag === HostComponent) {
73-
instance = node.stateNode;
74-
break;
75-
} else if (tag === HostRoot) {
76-
instance = node.stateNode.containerInfo;
77-
break;
69+
70+
if (!rootContainerInstance) {
71+
let node = fiber;
72+
while (node !== null) {
73+
const tag = node.tag;
74+
if (tag === HostComponent) {
75+
rootContainerInstance = node.stateNode;
76+
break;
77+
} else if (tag === HostRoot) {
78+
rootContainerInstance = node.stateNode.containerInfo;
79+
break;
80+
}
81+
node = node.return;
7882
}
79-
node = node.return;
8083
}
84+
8185
mountResponderInstance(
8286
responder,
8387
responderInstance,
8488
responderProps,
8589
responderState,
86-
((instance: any): Instance),
90+
((rootContainerInstance: any): Instance),
8791
);
8892
respondersMap.set(responder, responderInstance);
8993
}
@@ -96,6 +100,7 @@ function updateEventListener(
96100
ReactEventResponder<any, any>,
97101
ReactEventResponderInstance<any, any>,
98102
>,
103+
rootContainerInstance: null | Container,
99104
): void {
100105
let responder;
101106
let props;
@@ -127,15 +132,25 @@ function updateEventListener(
127132

128133
if (responderInstance === undefined) {
129134
// Mount (happens in either complete or commit phase)
130-
mountEventResponder(responder, listenerProps, fiber, respondersMap);
135+
mountEventResponder(
136+
responder,
137+
listenerProps,
138+
fiber,
139+
respondersMap,
140+
rootContainerInstance,
141+
);
131142
} else {
132143
// Update (happens during commit phase only)
133144
responderInstance.props = listenerProps;
134145
responderInstance.fiber = fiber;
135146
}
136147
}
137148

138-
export function updateEventListeners(listeners: any, fiber: Fiber): void {
149+
export function updateEventListeners(
150+
listeners: any,
151+
fiber: Fiber,
152+
rootContainerInstance: null | Container,
153+
): void {
139154
const visistedResponders = new Set();
140155
let dependencies = fiber.dependencies;
141156
if (listeners != null) {
@@ -153,10 +168,22 @@ export function updateEventListeners(listeners: any, fiber: Fiber): void {
153168
if (isArray(listeners)) {
154169
for (let i = 0, length = listeners.length; i < length; i++) {
155170
const listener = listeners[i];
156-
updateEventListener(listener, fiber, visistedResponders, respondersMap);
171+
updateEventListener(
172+
listener,
173+
fiber,
174+
visistedResponders,
175+
respondersMap,
176+
rootContainerInstance,
177+
);
157178
}
158179
} else {
159-
updateEventListener(listeners, fiber, visistedResponders, respondersMap);
180+
updateEventListener(
181+
listeners,
182+
fiber,
183+
visistedResponders,
184+
respondersMap,
185+
rootContainerInstance,
186+
);
160187
}
161188
}
162189
if (dependencies !== null) {

packages/react-reconciler/src/__tests__/ReactScope-test.internal.js

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -199,11 +199,11 @@ describe('ReactScope', () => {
199199
});
200200

201201
it('event responders can be attached to scopes', () => {
202+
let onKeyDown = jest.fn();
202203
const TestScope = React.unstable_createScope((type, props) => true);
203-
const onKeyDown = jest.fn();
204204
const ref = React.createRef();
205205
const useKeyboard = require('react-events/keyboard').useKeyboard;
206-
const Component = () => {
206+
let Component = () => {
207207
const listener = useKeyboard({
208208
onKeyDown,
209209
});
@@ -215,7 +215,29 @@ describe('ReactScope', () => {
215215
};
216216
ReactDOM.render(<Component />, container);
217217

218-
const target = createEventTarget(ref.current);
218+
let target = createEventTarget(ref.current);
219+
target.keydown({key: 'Q'});
220+
expect(onKeyDown).toHaveBeenCalledTimes(1);
221+
expect(onKeyDown).toHaveBeenCalledWith(
222+
expect.objectContaining({key: 'Q', type: 'keydown'}),
223+
);
224+
225+
onKeyDown = jest.fn();
226+
Component = () => {
227+
const listener = useKeyboard({
228+
onKeyDown,
229+
});
230+
return (
231+
<div>
232+
<TestScope listeners={listener}>
233+
<div ref={ref} />
234+
</TestScope>
235+
</div>
236+
);
237+
};
238+
ReactDOM.render(<Component />, container);
239+
240+
target = createEventTarget(ref.current);
219241
target.keydown({key: 'Q'});
220242
expect(onKeyDown).toHaveBeenCalledTimes(1);
221243
expect(onKeyDown).toHaveBeenCalledWith(

0 commit comments

Comments
 (0)