Skip to content

Commit 1638ddc

Browse files
committed
Guard against reused fibers in React Native commands
1 parent 342d9db commit 1638ddc

File tree

3 files changed

+52
-23
lines changed

3 files changed

+52
-23
lines changed

packages/react-native-renderer/src/ReactFabric.js

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -161,16 +161,14 @@ function dispatchCommand(handle: any, command: string, args: Array<any>) {
161161
'native component. Use React.forwardRef to get access to the underlying native component',
162162
);
163163
}
164-
165164
return;
166165
}
167166

168-
if (handle._internalInstanceHandle) {
169-
nativeFabricUIManager.dispatchCommand(
170-
handle._internalInstanceHandle.stateNode.node,
171-
command,
172-
args,
173-
);
167+
if (handle._internalInstanceHandle != null) {
168+
const {stateNode} = handle._internalInstanceHandle;
169+
if (stateNode != null) {
170+
nativeFabricUIManager.dispatchCommand(stateNode.node, command, args);
171+
}
174172
} else {
175173
UIManager.dispatchViewManagerCommand(handle._nativeTag, command, args);
176174
}
@@ -187,11 +185,11 @@ function sendAccessibilityEvent(handle: any, eventType: string) {
187185
return;
188186
}
189187

190-
if (handle._internalInstanceHandle) {
191-
nativeFabricUIManager.sendAccessibilityEvent(
192-
handle._internalInstanceHandle.stateNode.node,
193-
eventType,
194-
);
188+
if (handle._internalInstanceHandle != null) {
189+
const {stateNode} = handle._internalInstanceHandle;
190+
if (stateNode != null) {
191+
nativeFabricUIManager.sendAccessibilityEvent(stateNode.node, eventType);
192+
}
195193
} else {
196194
legacySendAccessibilityEvent(handle._nativeTag, eventType);
197195
}

packages/react-native-renderer/src/ReactNativeRenderer.js

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -161,12 +161,11 @@ function dispatchCommand(handle: any, command: string, args: Array<any>) {
161161
return;
162162
}
163163

164-
if (handle._internalInstanceHandle) {
165-
nativeFabricUIManager.dispatchCommand(
166-
handle._internalInstanceHandle.stateNode.node,
167-
command,
168-
args,
169-
);
164+
if (handle._internalInstanceHandle != null) {
165+
const {stateNode} = handle._internalInstanceHandle;
166+
if (stateNode != null) {
167+
nativeFabricUIManager.dispatchCommand(stateNode.node, command, args);
168+
}
170169
} else {
171170
UIManager.dispatchViewManagerCommand(handle._nativeTag, command, args);
172171
}
@@ -183,11 +182,11 @@ function sendAccessibilityEvent(handle: any, eventType: string) {
183182
return;
184183
}
185184

186-
if (handle._internalInstanceHandle) {
187-
nativeFabricUIManager.sendAccessibilityEvent(
188-
handle._internalInstanceHandle.stateNode.node,
189-
eventType,
190-
);
185+
if (handle._internalInstanceHandle != null) {
186+
const {stateNode} = handle._internalInstanceHandle;
187+
if (stateNode != null) {
188+
nativeFabricUIManager.sendAccessibilityEvent(stateNode.node, eventType);
189+
}
191190
} else {
192191
legacySendAccessibilityEvent(handle._nativeTag, eventType);
193192
}

packages/react-native-renderer/src/__tests__/ReactFabric-test.internal.js

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -387,6 +387,38 @@ describe('ReactFabric', () => {
387387
expect(nativeFabricUIManager.sendAccessibilityEvent).not.toBeCalled();
388388
});
389389

390+
it('should no-op if calling sendAccessibilityEvent on unmounted refs', () => {
391+
const View = createReactNativeComponentClass('RCTView', () => ({
392+
validAttributes: {foo: true},
393+
uiViewClassName: 'RCTView',
394+
}));
395+
396+
nativeFabricUIManager.sendAccessibilityEvent.mockReset();
397+
398+
let viewRef;
399+
act(() => {
400+
ReactFabric.render(
401+
<View
402+
ref={ref => {
403+
viewRef = ref;
404+
}}
405+
/>,
406+
11,
407+
);
408+
});
409+
const dangerouslyRetainedViewRef = viewRef;
410+
act(() => {
411+
ReactFabric.stopSurface(11);
412+
});
413+
414+
ReactFabric.sendAccessibilityEvent(
415+
dangerouslyRetainedViewRef,
416+
'eventTypeName',
417+
);
418+
419+
expect(nativeFabricUIManager.sendAccessibilityEvent).not.toBeCalled();
420+
});
421+
390422
it('should call FabricUIManager.measure on ref.measure', () => {
391423
const View = createReactNativeComponentClass('RCTView', () => ({
392424
validAttributes: {foo: true},

0 commit comments

Comments
 (0)