react-native-reanimated: [iOS] Animations don't always run on component initialization
Description
In reanimated 2.8.0, animations that run on component initialization don’t always animate. I can’t figure out why they work sometimes and don’t work other times. The strangest thing is that adding a console.log
within useAnimatedStyle
seems to fix the issue. Wrapping the call that sets the shared value to kick off the initial animation in a setTimeout
also seems to fix it (most of the time).
This bug does not occur in 2.3.1.
I believe this is the underlying issue behind this react-native-bottom-sheet
issue: https://github.com/gorhom/react-native-bottom-sheet/issues/925
Expected behavior
Animations run on component initialization.
(Below is with a console.log
added in useAnimatedStyle
):
https://user-images.githubusercontent.com/6730148/173665563-8df0791a-0a05-41de-a828-d9179f013849.MP4
Actual behavior & steps to reproduce
Create a component that has animations that run on initialization. Show/hide component. Animations run sometimes, but sometimes they just jump to final value (or partially animate).
(Without console.log
in useAnimatedStyle
):
https://user-images.githubusercontent.com/6730148/173665704-8c6f93eb-56e3-4cfd-88cd-7f64b1b02252.MP4
Snack or minimal code example
Run on iOS device to see issue: https://snack.expo.dev/@computerjazz/reanimated-init-bug
Package versions
2.8.0
name | version |
---|---|
react-native | 0.68.2 |
react-native-reanimated | 2.8.0 |
expo | 45 |
Affected platforms
- Android
- iOS
- Web
About this issue
- Original URL
- State: open
- Created 2 years ago
- Reactions: 23
- Comments: 26 (4 by maintainers)
tried the above, at first it looked like it worked, but it wasn’t reliable and sometimes the height still wouldn’t be set. Flickering was also still noticable when component fails to set height for the first part of the sequence. All in all it’s the same as adding a timeout, only in this case the duration is random and depends on how long the 0 duration animation took to finish
edit: nevermind, i had another component that i forgot to apply this method to inbetween two other components. It seems to be working reliably now!
edit2: well it works but there is visible flickering sometimes, like 1 in 10 cases
edit3: i don’t know what happened or changed, but i cannot reproduce this anymore, not even my own example above, which now works fine without any workarounds, on both iOS 16.2 simulator and physical iPhone 13 Pro on iOS 15.7. I’m still on reanimated v3.3.0,
edit4: no it still happens when JS thread is busy, with or without workarounds
Any update on this? I am suffering from the same issue with a fade in animation that is triggered on component mount in useEffect. console.logging the shared value is my only current work around. just triggering a () => {} function call does not solve my issue
Weird workaround
(hopefully it will work for you)
Observation:
Problems are with sudden changes during initialization. For example, in @lightrow’s example, he is changing
childrenHeight
from 0 to 500 instantly.use effect
it also just changes to 500(without any animation, so the same effect).withTiming(500)
;Solution
(for sudden changes)
Not so good
childrenHeight.value = withSequence(withTiming(0, {duration: 0}), withTiming(500, {duration: 0}))
This solution works for me, as it also has 0 total duration, and somehow using sequence fixes issue.
Problem: This works great when you are creating/rendering view, but if view is already there like on hot reload, screen will flicker. Because we are hiding view and again showing
Better solution
childrenHeight.value = withSequence(withTiming(501, {duration: 0}), withTiming(500, {duration: 0}))
This still happens in reanimated version
3.1.0