-
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix ReanimatedCommitHook
cloning
#6776
base: main
Are you sure you want to change the base?
Fix ReanimatedCommitHook
cloning
#6776
Conversation
Awesome work, @bartlomiejbloniarz - thanks for looking into this!! Tell me if this is ready to be tested and I can help! |
@chrfalch I think it's ready to be tested now. Thanks! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, but I'm still unsure whether getHasBeenPromoted
is a strong enough condition.
@j-piasecki Yeah, I'm also worried about that. I think that if there will be no issues during testing and this gets merged, we will release a RC version. |
While this patch resolves the modal issue for me on iOS, it seems to have cause a significant regression in |
@mhoran It breaks on both iOS and Android? |
Tested this on Android - this fixes the issue where modals are rendered off-screen or have 0 height/width causing them to be invisible while useAnimatedStyle exists elsewhere outside the Modal. However, this does not fix cases where Entering animations of an Animated.View inside a Modal seems to have 0 height/width/x/y, despite onLayout reporting the heights and widths properly.
One would assume these issues are somehow interlinked as they both are Modal related and cause zero'd out layout values. |
Yes, in slightly different ways. On iOS, I see two issues. First, issues with The second issue is an interaction with Simulator.Screen.Recording.-.iPad.mini.A17.Pro.-.2024-12-03.at.17.34.48.mp4On Android, I only see the I found that this seems to be some interaction with react-native-drawer-layout. The issues only seem to occur when the drawer is open when the app starts. I suspect this is because the drawer is still seen as "in front" of the I have created a reproducer here: https://github.com/mhoran/react-native-scratch/tree/reanimated-commit-hook-issue (reanimated-commit-hook-issue branch). Note this is using a local checkout of |
Is it possible to fix the root issue instead? It sounds like this is going against immutable tree updates — which is worrying to me because it is a fundamental constraint of the new RN architecture. It is worrying when Reanimated as a library keeps diverging from how RN works instead of getting closer to it. Looking at #6659 (comment):
This sounds like the proper fix should either be in RNScreens (does it mutate stuff it shouldn't?) or in how it interacts with Yoga. Can the fix be investigated there instead? |
It would be great to find a person on the React Native team who can help brainstorm the right integration layer between these libraries and ensure that they actually fit into the architecture. I presume it would be whoever added the commit hook functionality. |
cc @sammy-SC maybe you have thoughts on the right way to handle this |
Basically, the point I'm trying to make is that immutable tree updates is the entire premise of the Fabric architecture. It's a fundamental constraint. Every technical decision about how RN works will be relying on this constraint — both existing decisions and future decisions. So, in my understanding, it is not appropriate for a library to break this constraint and mutate these nodes — or worse, fight over who gets to mutate these nodes. If one library starts undermining this constraint, it isn't a good reason for another library to give in and undermine it even further. Instead, the concern needs to be brought upstream and a resolution within the architecture needs to be found. Reanimated is used very widely so if it starts violating the fundamental constraints of Fabric, this makes it hard for RN itself to change its implementation and take advantage of those constraints. Since changes that were previously unobservable would now become observable. I think this is very important and I want to make sure that this point of view is heard (you probably hear a lot of pragmatic "just fix it now somehow" so I want to balance that out a bit). Thanks. |
I agree with @gaearon as well. From Expo's side this is also something we feel very strongly about getting right - these libraries (REA/RNScreens) is as you say a fundamental part of almost all RN apps out there and will affect so many other libraries as well (React Navigation and a lot of other libs). I don't think the problem is mutating stuff that shouldn't be mutated - If I remember correctly the issue started as an optimization to make sure Reanimated didn't clone shadow nodes too often. The problem was that when running animations the code ended up cloning single shadow nodes multiple times in each pass - causing a performance degradation (correct me if I'm wrong, @bartlomiejbloniarz). A PR (#6214) was merged that optimized this to avoid "over-cloning" - but it seemed that the PR also introduced some side effects causing some layout issues that was mentioned in one of the first issues (#6659). A suggested way forward would be to remove the optimizations to create a baseline and verify that all the reported issues are working correct. Then we can measure and investigate which optimizations that should be made. As it is now, I also feel a bit insecure about what Dan also pointed out - the root cause of this problem (in the new architecture). |
@chrfalch Reverting #6214 wouldn't actually solve the problem. I mentioned in #6659 that this issue was also present in the old algorithm. Funnily enough it didn't show up in the Debug mode there, because we were updating I agree that the root cause of this issue is:
I am not sure when this behavior was introduced to RN, so that's something I need to examine. @gaearon let me explain in more detail what we are doing here, as we are not exactly breaking the
This PR is only about the algorithm that we use to modify the tree that we get in the But again, this approach comes with its own problems, that came up in testing, and it's very likely that this needs to be rethinked. |
Makes sense, thanks for explaining! Seems important that the team finds some approach that integrates nicely with RN itself. Does RN.Animated avoid these problems somehow? |
You explained it very well - thanks @bartlomiejbloniarz (also for looking into this is such a throughout way) |
Animated doesn't really go through the same pipeline, since it either applies transforms directly to views, when using |
@mhoran Could you test this version of this PR on your app? |
@bartlomiejbloniarz - sorry for the long wait - but I've now spent some time testing this issue and can verify that it now seems to be working correct in Debug/Release builds using the reproduction project - both with/without the last commit you've added. Great work! |
there seems to be an issue in Reanimated where it doesn't update layout info. so Pressables don't know when they are pressed. this adds a dummy style to force Reanimated to update the layout info. fixes #12324
On iOS, the issues I reported with the previous version of this patch look to be resolved with the latest patch. I still see a regression on new arch if padding is changed in the same Things are looking much better on Android as well. This seems to resolve issues I was having with Great work! |
One small issue remains with modals on both Android and iOS. On Android, I've seen the modal animate almost entirely off-screen to the top left corner before jumping to the correct position. On iOS, modals sometimes animate in from the bottom right instead of bottom center. Unfortunately I've found this incredibly difficult to reproduce, but there still seems to be some sort of issue with modals in particular. |
This issue seems to affect useAnimatedKeyboard also I am having performance issues with react-native-gifted-chat (which uses useAnimatedKeyboard and reanimated) since I moved to the new architecture. When I open the keyboard there is noticeable heavy lag similar to the issue with modals like gorham/bottom-sheet. |
How are you animating the view? If you have padding (or margin or height) in an animated style, it will cause flickering. This is a regression in new arch, but I'm not sure this issue is the root cause. Animated padding (margin and height) had poor performance on old arch (see #5685), but in new arch, even having a static padding, margin or heading value in an aimated style block will cause flickering. I worked around this by spotting my animated styles in two (one for the transform, one for padding), and ensuring that the padding style updates as infrequently as possible. |
Hey @mhoran yeah my bad I think you're right as I just applied the new PR as a patch to the latest RC and it is not resolving my issues with gorhom/bottom-sheet lagging and lack of space at the bottom + the keyboard issue I mentioned I made this assumption based on the other lagging issues related to this PR and reading this issue in gorhom bottom sheet gorhom/react-native-bottom-sheet#2046 It is also not resolving my keyboard issues in gifted chat either, the code is from gifted chat and is here https://github.com/FaridSafi/react-native-gifted-chat/blob/master/src/GiftedChat.tsx |
@mhoran Do you see the issue with modal animation only with this PR or is it something that also happens on main? |
On Android, modals always animate to the top left corner and remain off screen. With this PR, they only animate to the top left corner sometimes, and always wind up in the correct place. The animation is just wrong, sometimes. On iOS, this PR seems to introduce a regression, but it's very hard to tell. I only see modal issues on iOS when the window has been resized to less than full screen using Stage Manager. The modals display in odd places, and do not show entirely on screen. As such, it's very difficult to tell where it is animating from, since the full modal is not visible. It could be that this issue exists on main or it could be a regression, and reproducing is very tricky. |
When testing with the modal bug repro reported here: #6659, the invalid modal rendering is still visible during the modal entrance animation. Test codeimport {useState} from 'react';
import {Button, Modal, SafeAreaView, StatusBar, View} from 'react-native';
import Animated, {useAnimatedStyle} from 'react-native-reanimated';
export default function App() {
const [visible, setVisible] = useState(false);
const animatedStyle = useAnimatedStyle(() => ({
transform: [{translateX: 0}],
}));
return (
<SafeAreaView
style={{
flex: 1,
backgroundColor: '#fff',
padding: 16,
}}>
<StatusBar />
<View
style={{
paddingVertical: 16,
}}
/>
<Button
title="Open Modal"
onPress={() => {
setVisible(true);
}}
/>
<Animated.View style={animatedStyle} />
<Modal visible={visible} animationType="slide">
<View
style={{
padding: 32,
backgroundColor: 'pink',
}}/>
</Modal>
</SafeAreaView>
);
} On the following video, the entrance animation is 8 frames long. trimmed_repro.mp4 |
As mentioned in react-navigation/react-navigation@9831292#commitcomment-150759476, this patch no longer worked for me on iOS once I upgraded react-native-drawer-layout to 4.1.1. I see issues with ScrollViews and cannot open the keyboard, as if |
Summary
This PR changes the way the
ShadowTree
is updated in the commit hook. Previously we would always clone the updated nodes, leading to RN also cloning the remaining nodes (some of them have never been mounted, as we are in the commit hook).When RN clones uncommited nodes, it doesn't clone the state from the source node, but instead uses last mounted state, meaning that some of the updates will be lost.
To fix that, we don't clone unmounted
ShadowNodes
but instead change them in place. To recognize if a node was mounted we use thegetHasBeenPromoted
method.This change needs to be well tested as modifying nodes in place has to be done carefully, since it's not really the intended way.
fixes #6659
Test plan
Check behaviour of the repro from #6659, ChessboardExample, BokehExample