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)

Commits related to this issue

Most upvoted comments

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.

  • He could have directly initialize the shared value to 500, because in use effect it also just changes to 500(without any animation, so the same effect).
  • And animations also work, like 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