Commit ab2a303
authored
fix(Android,Fabric): prevent header subview disappearance when using
## Description
* [x] Should be merged after #2811 & rebased.
When setting subviews via `setOptions` from `useEffect` hook in a
component, the first frame received might be computed by native
layout & completely invalid (zero height). RN layout is the source of a
subview **size** (not origin). When we send such update with zero height
Yoga might (or might not, depending on exact update timing in relation
to other ongoing commits / layouts) set the subview height to 0!
This causes the subview to become invisible & we want to avoid that.
This had not been a problem before
#2696,
because we would filter out
this kind of frame in the `setSize` guard in the
`ComponentDescriptor.adopt` method of the `HeaderSubview`.
#2696
allowed
for zero-sized frames for other, unrelated reason & we must allow these
as long as they come from React Native layout & not native one.
## Changes
We now filter these invalid frames on the side of HostTree, by detecting
whether React has measured the subview or not.
## Test code and steps to reproduce
I've tested the problem on slightly modified `Test2466`:
<details>
<summary>Code snippet</summary>
```tsx
import { NavigationContainer } from '@react-navigation/native';
import { createNativeStackNavigator, NativeStackNavigationProp } from '@react-navigation/native-stack';
import React from 'react';
import { findNodeHandle, Text, View } from 'react-native';
import PressableWithFeedback from '../shared/PressableWithFeedback';
type StackParamList = {
Home: undefined,
}
type RouteProps = {
navigation: NativeStackNavigationProp<StackParamList>;
}
const Stack = createNativeStackNavigator<StackParamList>();
function HeaderTitle(): React.JSX.Element {
return (
<PressableWithFeedback
onLayout={event => {
const { x, y, width, height } = event.nativeEvent.layout;
console.log('Title onLayout', { x, y, width, height });
}}
onPressIn={() => {
console.log('Pressable onPressIn');
}}
onPress={() => console.log('Pressable onPress')}
onPressOut={() => console.log('Pressable onPressOut')}
onResponderMove={() => console.log('Pressable onResponderMove')}
ref={node => {
console.log(findNodeHandle(node));
node?.measure((x, y, width, height, pageX, pageY) => {
console.log('header component measure', { x, y, width, height, pageX, pageY });
});
}}
>
<View style={{ height: 40, justifyContent: 'center', alignItems: 'center' }}>
<Text style={{ alignItems: 'center' }}>Regular Pressable</Text>
</View>
</PressableWithFeedback>
);
}
function HeaderLeft(): React.JSX.Element {
return (
<HeaderTitle />
);
}
function Home({ navigation }: RouteProps): React.JSX.Element {
React.useEffect(() => {
console.log('calling setOptions in useEffect');
navigation.setOptions({
//headerTitle: HeaderTitle,
headerLeft: HeaderLeft,
//headerRight: HeaderLeft,
});
}, [navigation]);
return (
<View style={{ flex: 1, backgroundColor: 'rgba(0, 0, 0, .8)' }}
>
<View style={{ flex: 1, alignItems: 'center', marginTop: 48 }}>
<PressableWithFeedback
onPressIn={() => console.log('Pressable onPressIn')}
onPress={() => console.log('Pressable onPress')}
onPressOut={() => console.log('Pressable onPressOut')}
>
<View style={{ height: 40, width: 200, justifyContent: 'center', alignItems: 'center' }}>
<Text style={{ alignItems: 'center' }}>Regular Pressable</Text>
</View>
</PressableWithFeedback>
</View>
</View>
);
}
function App(): React.JSX.Element {
return (
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen
name="Home"
component={Home}
options={{
//headerTitle: HeaderTitle,
//headerLeft: HeaderLeft,
//headerRight: HeaderLeft,
}}
/>
</Stack.Navigator>
</NavigationContainer>
);
}
export default App;
```
</details>
## Checklist
- [x] Included code example that can be used to test this change
- [x] Ensured that CI passes
(7d3205e)setOptions (#2812)1 parent b1e9c71 commit ab2a303
1 file changed
Lines changed: 19 additions & 2 deletions
Lines changed: 19 additions & 2 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
10 | 10 | | |
11 | 11 | | |
12 | 12 | | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
13 | 21 | | |
14 | 22 | | |
15 | 23 | | |
| |||
22 | 30 | | |
23 | 31 | | |
24 | 32 | | |
25 | | - | |
| 33 | + | |
26 | 34 | | |
27 | 35 | | |
| 36 | + | |
28 | 37 | | |
29 | 38 | | |
30 | 39 | | |
| |||
44 | 53 | | |
45 | 54 | | |
46 | 55 | | |
47 | | - | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
48 | 65 | | |
49 | 66 | | |
50 | 67 | | |
| |||
0 commit comments