-
Notifications
You must be signed in to change notification settings - Fork 25.1k
Comparing changes
Open a pull request
base repository: facebook/react-native
base: v0.77.0-rc.2
head repository: facebook/react-native
compare: v0.77.0-rc.4
- 14 commits
- 53 files changed
- 8 contributors
Commits on Dec 10, 2024
-
Configuration menu - View commit details
-
Copy full SHA for 77b9c55 - Browse repository at this point
Copy the full SHA 77b9c55View commit details
Commits on Dec 16, 2024
-
Disable weak event emitter in AttributedString for Mac Catalyst (#48225)
Summary: Pull Request resolved: #48225 Fixes #47762 The weak event emitter in AttributedString attributes is causing a serialization error when typing into a TextInput in a Mac Catalyst build. We can resolve this by not putting the event emitters in the attributed string, but this is likely to cause other issues with event handling for nested <Text> components. ## Changelog [iOS][Fixed] - Workaround for Mac Catalyst TextInput crash due to serialization attempt of WeakEventEmitter Reviewed By: NickGerleman Differential Revision: D66664583 fbshipit-source-id: efdfbcb0db4d5e6b9bf7c14f9bbb221faae2d724
Configuration menu - View commit details
-
Copy full SHA for 840382d - Browse repository at this point
Copy the full SHA 840382dView commit details -
Enable hermes debugger by configuration type instead of configuration…
… name (#48174) Summary: Fixes an [issue](#48168) where only iOS configurations with "Debug" in the name are configured to use the hermes debugger. ## Changelog: <!-- Help reviewers and the release process by writing your own changelog entry. Pick one each for the category and type tags: For more details, see: https://reactnative.dev/contributing/changelogs-in-pull-requests --> [IOS] [FIXED] - Enable hermes debugger by configuration type instead of configuration name Pull Request resolved: #48174 Test Plan: Added new test scenarios that all pass: ``` ruby -Itest packages/react-native/scripts/cocoapods/__tests__/utils-test.rb Loaded suite packages/react-native/scripts/cocoapods/__tests__/utils-test Started Finished in 0.336047 seconds. ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 56 tests, 149 assertions, 0 failures, 0 errors, 0 pendings, 0 omissions, 0 notifications 100% passed ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 166.64 tests/s, 443.39 assertions/s ``` In a personal project with the following configurations: ``` project 'ReactNativeProject', { 'Local' => :debug, 'Development' => :release, 'Staging' => :release, 'Production' => :release, } ``` I added the following to my Podfile: ``` installer.pods_project.targets.each do |target| target.build_configurations.each do |config| puts "#{config.name} is debug? #{config.type == :debug}" end end ``` To confirm that my logic is correct: ``` Local is debug? true Development is debug? false Staging is debug? false Production is debug? false ``` Reviewed By: robhogan Differential Revision: D66962860 Pulled By: cipolleschi fbshipit-source-id: 7bd920e123c9064c8a1b5d45df546ff5d2a7d8be
Configuration menu - View commit details
-
Copy full SHA for b153ec8 - Browse repository at this point
Copy the full SHA b153ec8View commit details -
Skip hidden folders when looking for third party components (#48182)
Summary: Pull Request resolved: #48182 Maintainers from SVG reached out because of an edge case they inencountered when generating the ComponentProvider. In their setup, they had a `.git` folder in the repo and the algorithm was spending a lot of time crawling the git folder. In general, we should avoid crawling hidden folders. This change fix that. ## Changelog: [General][Fixed] - Skip hidden folders when looking for third party components. Reviewed By: javache Differential Revision: D66959345 fbshipit-source-id: 992a79f3cff22cd6a459e0272c8140bc329888da
Configuration menu - View commit details
-
Copy full SHA for 621f13f - Browse repository at this point
Copy the full SHA 621f13fView commit details -
Fix handling removal of transitioning views (#47634)
Summary: Related PR in `react-native-screens`: * software-mansion/react-native-screens#2495 Additional context: * [my detailed explanation of **one of the issues**](software-mansion/react-native-screens#2495 (comment)) * [Android Developer: ViewGroup.startViewTransition docs](https://developer.android.com/reference/android/view/ViewGroup#startViewTransition(android.view.View)) On Android view groups can be marked as "transitioning" with a `ViewGroup.startViewTransition` call. This effectively ensures, that in case a view group is marked with this call and its children are removed, they will be still drawn until `endViewTransition` is not called. This mechanism is implemented in Android by [keeping track of "transitioning" children in auxiliary `mTransitioningViews` array](https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/view/ViewGroup.java#7178). Then when such "transitioning" child is removed, [it is removed from children array](https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/view/ViewGroup.java#5595) but it's [parent-child relationship is not cleared](https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/view/ViewGroup.java#5397) and it is still retained in the auxiliary array. Having that established we can proceed with problem description. https://github.com/user-attachments/assets/d0356bf5-2f17-4b06-ba53-bfca659a1071 <details> <summary>Full code</summary> ```javascript import { NavigationContainer } from 'react-navigation/native'; import React from 'react'; import { createNativeStackNavigator } from 'react-navigation/native-stack'; import { enableScreens } from 'react-native-screens'; import { StyleSheet, Text, View, FlatList, Button, ViewProps, Image, FlatListProps, findNodeHandle, } from 'react-native'; enableScreens(true); function Item({ children, ...props }: ViewProps) { return ( <View style={styles.item} {...props}> <Image source={require('../assets/trees.jpg')} style={styles.image} /> <Text style={styles.text}>{children}</Text> </View> ); } function Home({ navigation }: any) { return ( <View style={styles.container}> <Button title="Go to List" onPress={() => navigation.navigate('List')} /> </View> ); } function ListScreenSimplified({secondVisible}: {secondVisible?: (visible: boolean) => void}) { const containerRef = React.useRef<View>(null); const innerViewRef = React.useRef<View>(null); const childViewRef = React.useRef<View>(null); React.useEffect(() => { if (containerRef.current != null) { const tag = findNodeHandle(containerRef.current); console.log(`Container has tag [${tag}]`); } if (innerViewRef.current != null) { const tag = findNodeHandle(innerViewRef.current); console.log(`InnerView has tag [${tag}]`); } if (childViewRef.current != null) { const tag = findNodeHandle(childViewRef.current); console.log(`ChildView has tag [${tag}]`); } }, [containerRef.current, innerViewRef.current, childViewRef.current]); return ( <View ref={containerRef} style={{ flex: 1, backgroundColor: 'slateblue', overflow: 'hidden' }} removeClippedSubviews={false}> <View ref={innerViewRef} removeClippedSubviews style={{ height: '100%' }}> <View ref={childViewRef} style={{ backgroundColor: 'pink', width: '100%', height: 50 }} removeClippedSubviews={false}> {secondVisible && (<Button title='Hide second' onPress={() => secondVisible(false)} />)} </View> </View> </View> ); } function ParentFlatlist(props: Partial<FlatListProps<number>>) { return ( <FlatList data={Array.from({ length: 30 }).fill(0) as number[]} renderItem={({ index }) => { if (index === 10) { return <NestedFlatlist key={index} />; } else if (index === 15) { return <ExtraNestedFlatlist key={index} />; } else if (index === 20) { return <NestedFlatlist key={index} horizontal />; } else if (index === 25) { return <ExtraNestedFlatlist key={index} horizontal />; } else { return <Item key={index}>List item {index + 1}</Item>; } }} {...props} /> ); } function NestedFlatlist(props: Partial<FlatListProps<number>>) { return ( <FlatList style={[styles.nestedList, props.style]} data={Array.from({ length: 10 }).fill(0) as number[]} renderItem={({ index }) => ( <Item key={'nested' + index}>Nested list item {index + 1}</Item> )} {...props} /> ); } function ExtraNestedFlatlist(props: Partial<FlatListProps<number>>) { return ( <FlatList style={styles.nestedList} data={Array.from({ length: 10 }).fill(0) as number[]} renderItem={({ index }) => index === 4 ? ( <NestedFlatlist key={index} style={{ backgroundColor: '#d24729' }} /> ) : ( <Item key={'nested' + index}>Nested list item {index + 1}</Item> ) } {...props} /> ); } const Stack = createNativeStackNavigator(); export default function App(): React.JSX.Element { return ( <NavigationContainer> <Stack.Navigator screenOptions={{ animation: 'slide_from_right' }}> <Stack.Screen name="Home" component={Home} /> <Stack.Screen name="List" component={ListScreenSimplified}/> </Stack.Navigator> </NavigationContainer> ); } export function AppSimple(): React.JSX.Element { const [secondVisible, setSecondVisible] = React.useState(false); return ( <View style={{ flex: 1, backgroundColor: 'lightsalmon' }}> {!secondVisible && ( <View style={{ flex: 1, backgroundColor: 'lightblue' }} > <Button title='Show second' onPress={() => setSecondVisible(true)} /> </View> )} {secondVisible && ( <ListScreenSimplified secondVisible={setSecondVisible} /> )} </View> ); } const styles = StyleSheet.create({ container: { flex: 1, alignItems: 'center', justifyContent: 'center', }, nestedList: { backgroundColor: '#FFA07A', }, item: { flexDirection: 'row', alignItems: 'center', padding: 10, gap: 10, }, text: { fontSize: 24, fontWeight: 'bold', color: 'black', }, image: { width: 50, height: 50, }, }); ``` </details> Explanation (copied from [here](software-mansion/react-native-screens#2495 (comment))): I've debugged this for a while now & I have good understanding of what's going on. This bug is caused by our usage of `startViewTransition` and its implications. We use it well, however React does not account for case that some view might be in transition. Error mechanism is as follows: 1. Let's have initially simple stack with two screens: "A, B". This is component rendered under "B": ```javascript <View //<-- ContainerView (CV) removeClippedSubviews={false} style={{ flex: 1, backgroundColor: 'slateblue', overflow: 'hidden' }}> <View removeClippedSubviews style={{ height: '100%' }}> // <--- IntermediateView (IV) <View removeClippedSubviews={false} style={{ backgroundColor: 'pink', width: '100%', height: 50 }} /> // <--- ChildView (ChV) </View> </View> ``` 2. We press the back button. 3. We're on Fabric, therefore subtree of B gets destroyed before B itself is unmounted -> in our commit hook we detect that the screen B will be unmounted & we mark every node under B as transitioning by calling `startViewTransition`. 4. React Mounting stage starts, view hierarchy is disassembled in bottom-up fashion (leafs first). 5. ReactViewGroupManager receives MountItem to detach ChV from IV. 6. A call to [`IV.removeView(ChV)` is made](https://github.com/facebook/react-native/blob/9c11d7ca68c5c62ab7bab9919161d8417e96b28b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactClippingViewManager.kt#L58-L73), which effectively removes ChV from `IV.children`, ***HOWEVER*** it does not clear `ChV.parent`, meaning that after the call, `ChV.parent == IV`. This happens, due to view being marked as in-transition by our call to `startViewTransition`. If the view is not marked as in-transition this parent-child relationship is removed. 7. IV has `removeClippedSubviews` enabled, therefore a [call to `IV.removeViewWithSubviewsClippingEnabled(ChV)` is made](https://github.com/facebook/react-native/blob/9c11d7ca68c5c62ab7bab9919161d8417e96b28b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactClippingViewManager.kt#L68). [This function](https://github.com/facebook/react-native/blob/9c11d7ca68c5c62ab7bab9919161d8417e96b28b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewGroup.java#L726-L744) does effectively two things: 1. if the ChV has parent (interpretation: it has not yet been detached from parent), we compute it's index in `IV.children` (Android.ViewGroup's state) and remove it from the array, 2. remove the ChV from `mAllChildren` array (this is state maintained by ReactViewGroup for purposes of implementing the "subview clipping" mechanism". The crash happens in 7.1, because ChV has been removed from `IV.children` in step 6, but the parent-child relationship has not been broken up there. Under usual circumstances (this is my hypothesis now, yet unconfirmed) 7.1 does not execute, because `ChV.parent` is nulled in step no. 6. Transitions. On Fabric, when some subtree is unmounted, views in the subtree are unmounted in bottom-up order. This leads to uncomfortable situation, where our components (react-native-screens), who want to drive & manage transitions are notified that their children will be removed after the subtrees mounted in screen subviews are already disassembled. **If we start animation in this very moment we will have staggering effect of white flash** [(issue)](software-mansion/react-native-screens#1685) (we animate just the screen with white background without it's children). This was not a problem on Paper, because the order of subtree disassembling was opposite - top-down. While we've managed to workaround this issue on Fabric using `MountingTransactionObserving` protocol on iOS and a commit hook on Android (we can inspect mutations in incoming transaction before it starts being applied) we still need to prevent view hierarchy from being disassembled in the middle of transition (on Paper this has also been less of an issue) - and this is where `startViewTransition` comes in. It allows us to draw views throughout transition after React Native removes them from HostTree model. On iOS we exchange subtree for its snapshot for transition time, however this approach isn't feasible on Android, because [snapshots do not capture shadows](https://stackoverflow.com/questions/42212600/android-screenshot-of-view-with-shadow). [Android does not expose a method to verify whether a view is in transition](https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/view/ViewGroup.java#7162) (it has `package` visibility), therefore we need to retrieve this information with some workaround. I see two posibilities: * first approach would be to override `startViewTransition` & `endViewTransition` in ReactViewGroup and keep the state on whether the view is transitioning there, * second possible approach would be as follows: we can check for "transitioning" view by checking whether a view has parent but is not it's parent child (this **should** be reliable), Having information on whether the view is in transition or not, we can prevent multiple removals of the same view in every call site (currently only in `removeViewAt` if `parent.removeClippingSubviews == true`). Another option would be to do just as this PR does: having in mind this "transitioning" state we can pass a flag to `removeViewWithSubviewClippingEnabled` and prevent duplicated removal from parent if we already know that this has been requested. I can also add override of this method: ```java /*package*/ void removeViewWithSubviewClippingEnabled(View view) { this.removeViewWithSubviewClippingEnabled(view, false); } ``` to make this parameter optional. [ANDROID] [FIXED] - Handle removal of in-transition views. Pull Request resolved: #47634 Test Plan: WIP WIP Reviewed By: javache Differential Revision: D66539065 Pulled By: tdn120 fbshipit-source-id: cf1add67000ebd1b5dfdb2048461a55deac10b16
Configuration menu - View commit details
-
Copy full SHA for 81aaf46 - Browse repository at this point
Copy the full SHA 81aaf46View commit details -
Revert "Include autolinkin.h in OnLoad.cpp only if it exists (#47875)"
This reverts commit 5b2bbb8.
Configuration menu - View commit details
-
Copy full SHA for 125b0f4 - Browse repository at this point
Copy the full SHA 125b0f4View commit details -
Configuration menu - View commit details
-
Copy full SHA for d4941c7 - Browse repository at this point
Copy the full SHA d4941c7View commit details -
Configuration menu - View commit details
-
Copy full SHA for c4c52fb - Browse repository at this point
Copy the full SHA c4c52fbView commit details -
Configuration menu - View commit details
-
Copy full SHA for 6b22412 - Browse repository at this point
Copy the full SHA 6b22412View commit details -
Configuration menu - View commit details
-
Copy full SHA for e7c4490 - Browse repository at this point
Copy the full SHA e7c4490View commit details
Commits on Dec 17, 2024
-
Configuration menu - View commit details
-
Copy full SHA for 0840eab - Browse repository at this point
Copy the full SHA 0840eabView commit details -
Configuration menu - View commit details
-
Copy full SHA for 4370860 - Browse repository at this point
Copy the full SHA 4370860View commit details
Commits on Dec 23, 2024
-
Restore subclipping view removal (#48329)
Summary: Pull Request resolved: #48329 With the call to `removeView()` removed from `ReactViewClippingManager` in #47634, we're seeing views erroneously sticking around in the layout. While `removeViewWithSubviewClippingEnabled()` calls `removeViewsInLayout()`, it does not trigger the corresponding side effects of [removeView()](https://android.googlesource.com/platform/frameworks/base/+/refs/tags/android-15.0.0_r9/core/java/android/view/ViewGroup.java#5501): ``` public void removeView(View view) { if (removeViewInternal(view)) { --> requestLayout(); --> invalidate(true); } } ``` To compensate, flip `removeViewsInLayout()` to [`removeViews()`](https://android.googlesource.com/platform/frameworks/base/+/refs/tags/android-15.0.0_r9/core/java/android/view/ViewGroup.java#5562), which will ensure layout. Changelog: [Android][Fixed] Restore layout/invalidate during ReactViewClippingManager.removeViewAt() Reviewed By: javache Differential Revision: D67398971 fbshipit-source-id: b100db468cc3be6ddc6edd6c6d078a8a0b59a2c1
2Configuration menu - View commit details
-
Copy full SHA for e3970a4 - Browse repository at this point
Copy the full SHA e3970a4View commit details -
Configuration menu - View commit details
-
Copy full SHA for b0d9ef8 - Browse repository at this point
Copy the full SHA b0d9ef8View commit details
This comparison is taking too long to generate.
Unfortunately it looks like we can’t render this comparison for you right now. It might be too big, or there might be something weird with your repository.
You can try running this command locally to see the comparison on your machine:
git diff v0.77.0-rc.2...v0.77.0-rc.4