Skip to content

Commit 138de6c

Browse files
committed
Skip cloneElement for Fragment children in TouchableHighlight
React emits "Invalid prop `style` supplied to `React.Fragment`" when a Fragment is passed as a child to TouchableHighlight, because the render path unconditionally calls `cloneElement(child, {style})`. Fragments ignore `style` at runtime anyway, so skip the clone and render the Fragment through directly when `child.type === React.Fragment`. Fixes #54933.
1 parent 5f69a91 commit 138de6c

2 files changed

Lines changed: 43 additions & 6 deletions

File tree

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

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -376,12 +376,14 @@ class TouchableHighlightImpl extends React.Component<
376376
testID={this.props.testID}
377377
ref={this.props.hostRef}
378378
{...eventHandlersWithoutBlurAndFocus}>
379-
{cloneElement(child, {
380-
style: StyleSheet.compose(
381-
child.props.style,
382-
this.state.extraStyles?.child,
383-
),
384-
})}
379+
{child.type === React.Fragment
380+
? child
381+
: cloneElement(child, {
382+
style: StyleSheet.compose(
383+
child.props.style,
384+
this.state.extraStyles?.child,
385+
),
386+
})}
385387
{__DEV__ ? (
386388
<PressabilityDebugView color="green" hitSlop={this.props.hitSlop} />
387389
) : null}

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

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -395,6 +395,41 @@ describe('<TouchableHighlight>', () => {
395395
</rn-view>,
396396
);
397397
});
398+
399+
// Regression test for #54933: cloning a `React.Fragment` with a `style`
400+
// prop triggers "Invalid prop `style` supplied to `React.Fragment`".
401+
it('renders a Fragment child without console errors', () => {
402+
const originalConsoleError = console.error;
403+
const mockConsoleError = jest.fn();
404+
// $FlowFixMe[cannot-write]
405+
console.error = mockConsoleError;
406+
407+
try {
408+
const root = Fantom.createRoot();
409+
410+
Fantom.runTask(() => {
411+
root.render(
412+
<TouchableHighlight>
413+
<React.Fragment>
414+
<Text>First</Text>
415+
<Text>Second</Text>
416+
</React.Fragment>
417+
</TouchableHighlight>,
418+
);
419+
});
420+
421+
expect(root.getRenderedOutput().toJSX()).toEqual(
422+
<rn-view>
423+
<rn-paragraph>First</rn-paragraph>
424+
<rn-paragraph>Second</rn-paragraph>
425+
</rn-view>,
426+
);
427+
expect(mockConsoleError).not.toHaveBeenCalled();
428+
} finally {
429+
// $FlowFixMe[cannot-write]
430+
console.error = originalConsoleError;
431+
}
432+
});
398433
});
399434
});
400435

0 commit comments

Comments
 (0)