Skip to content

Commit 0f69734

Browse files
committed
Throw on React.Fragment child in TouchableHighlight
Fixes #54933. TouchableHighlight injects the underlay style onto its single child via cloneElement. React.Fragment cannot accept that style, so React emits a generic "Invalid prop `style` supplied to `React.Fragment`" warning and the highlight effect is silently broken. Throw an actionable error via invariant naming the component, the constraint, and the fix (wrap in a View). Matches the class doc, which already specifies that multiple children must be wrapped in a View.
1 parent 5f69a91 commit 0f69734

2 files changed

Lines changed: 40 additions & 0 deletions

File tree

packages/react-native/Libraries/Components/Touchable/TouchableHighlight.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import Pressability, {
1919
import {PressabilityDebugView} from '../../Pressability/PressabilityDebug';
2020
import StyleSheet, {type ViewStyleProp} from '../../StyleSheet/StyleSheet';
2121
import Platform from '../../Utilities/Platform';
22+
import invariant from 'invariant';
2223
import * as React from 'react';
2324
import {cloneElement} from 'react';
2425

@@ -304,6 +305,11 @@ class TouchableHighlightImpl extends React.Component<
304305

305306
render(): React.Node {
306307
const child = React.Children.only<$FlowFixMe>(this.props.children);
308+
invariant(
309+
child.type !== React.Fragment,
310+
'TouchableHighlight does not support React.Fragment as a child. ' +
311+
'Wrap the children in a single host element such as <View>.',
312+
);
307313

308314
// BACKWARD-COMPATIBILITY: Focus and blur events were never supported before
309315
// adopting `Pressability`, so preserve that behavior.

packages/react-native/Libraries/Components/Touchable/__tests__/TouchableHighlight-itest.js

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -395,6 +395,40 @@ describe('<TouchableHighlight>', () => {
395395
</rn-view>,
396396
);
397397
});
398+
399+
// Regression test for #54933: a `React.Fragment` cannot accept the
400+
// underlay style applied via `cloneElement`, so the highlight effect
401+
// is silently broken. Surface that as an actionable error instead.
402+
it('errors when given a React.Fragment as a child', () => {
403+
const originalConsoleError = console.error;
404+
const mockConsoleError = jest.fn();
405+
// $FlowFixMe[cannot-write]
406+
console.error = mockConsoleError;
407+
408+
try {
409+
const root = Fantom.createRoot();
410+
411+
Fantom.runTask(() => {
412+
root.render(
413+
<TouchableHighlight>
414+
<React.Fragment>
415+
<Text>First</Text>
416+
<Text>Second</Text>
417+
</React.Fragment>
418+
</TouchableHighlight>,
419+
);
420+
});
421+
422+
expect(mockConsoleError).toHaveBeenCalled();
423+
const reportedError = mockConsoleError.mock.calls[0][0];
424+
expect(reportedError.message).toContain(
425+
'TouchableHighlight does not support React.Fragment as a child',
426+
);
427+
} finally {
428+
// $FlowFixMe[cannot-write]
429+
console.error = originalConsoleError;
430+
}
431+
});
398432
});
399433
});
400434

0 commit comments

Comments
 (0)