react-native icon indicating copy to clipboard operation
react-native copied to clipboard

Listeners are not fired on combined Animated values using Animated operators

Open endlessqt opened this issue 10 months ago • 10 comments

Description

When you trying to combine Animated values with Animated operators e.g. addition, multiplication you cannot listen to this values with addListener, callbacks are never fired. As fas as i can tell it works fine on version 0.77.1, so its regression for 0.78.0 version. I've tested on Android only using emulator. I'm adding a reproducible example app with comments to code. Thank you in advance for the help.

Steps to reproduce

  1. Install deps with yarn install
  2. Run metro with yarn start
  3. Run android app with yarn android
  4. Click button fade in View
  5. Notice how red square is scaling in size and view with text appearing on the screen
  6. Check metro/devtools logs. There are no logs for scale animation, but listener is added to Animated Value created with Animated.add. So listener callback are never fired for scale animation, but animation on view works fine.

React Native Version

0.78.0

Affected Platforms

Runtime - Android

Output of npx @react-native-community/cli info

System:
  OS: macOS 15.3
  CPU: (12) arm64 Apple M2 Pro
  Memory: 135.88 MB / 16.00 GB
  Shell:
    version: "5.9"
    path: /bin/zsh
Binaries:
  Node:
    version: 22.14.0
    path: ~/.nvm/versions/node/v22.14.0/bin/node
  Yarn: Not Found
  npm:
    version: 10.9.2
    path: ~/.nvm/versions/node/v22.14.0/bin/npm
  Watchman:
    version: 2024.12.02.00
    path: /opt/homebrew/bin/watchman
Managers:
  CocoaPods: Not Found
SDKs:
  iOS SDK: Not Found
  Android SDK: Not Found
IDEs:
  Android Studio: 2024.2 AI-242.23726.103.2422.12816248
  Xcode:
    version: /undefined
    path: /usr/bin/xcodebuild
Languages:
  Java:
    version: 17.0.14
    path: /usr/bin/javac
  Ruby:
    version: 3.4.1
    path: /opt/homebrew/opt/ruby/bin/ruby
npmPackages:
  "@react-native-community/cli":
    installed: 15.0.1
    wanted: 15.0.1
  react:
    installed: 19.0.0
    wanted: 19.0.0
  react-native:
    installed: 0.78.0
    wanted: 0.78.0
  react-native-macos: Not Found
npmGlobalPackages:
  "*react-native*": Not Found
Android:
  hermesEnabled: true
  newArchEnabled: true
iOS:
  hermesEnabled: Not found
  newArchEnabled: false

Stacktrace or Logs

No crashes detected

Reproducer

https://github.com/endlessqt/rn-animated-values-listeneres-0.78

Screenshots and Videos

No response

endlessqt avatar Feb 27 '25 13:02 endlessqt

  • Notice how red square is scaling in size and view with text appearing on the screen

Thanks for providing the repro @endlessqt

Two questions:

  1. Can you share a video of the problem?
  2. Is the problem also happening on the Old Arch?

cortinico avatar Feb 27 '25 16:02 cortinico

@cortinico Thank you for response.

  1. Do you want a video of me showing logs inside devtools? I mean the problem is not on the screen. View layer is working completely fine. Scale animation works, fade animation works. The callback of addListener on Animated.Value created with Animated.add is not firing when Animated.Value changes.
  2. I can check, do i need to just set newArchEnabled=false in my gradle.properties?

endlessqt avatar Feb 27 '25 17:02 endlessqt

  • Do you want a video of me showing logs inside devtools? I mean the problem is not on the screen. View layer is working completely fine. Scale animation works, fade animation works. The callback of addListener on Animated.Value created with Animated.add is not firing when Animated.Value changes.

Ah I understand what's happening. Still having a video with emulator and console of Before (0.77) and After (0.78) could really help as we try to find an owner for this.

  • I can check, do i need to just set newArchEnabled=false in my gradle.properties?

Correct 👍

cortinico avatar Feb 27 '25 18:02 cortinico

  • Do you want a video of me showing logs inside devtools? I mean the problem is not on the screen. View layer is working completely fine. Scale animation works, fade animation works. The callback of addListener on Animated.Value created with Animated.add is not firing when Animated.Value changes.

Ah I understand what's happening. Still having a video with emulator and console of Before (0.77) and After (0.78) could really help as we try to find an owner for this.

  • I can check, do i need to just set newArchEnabled=false in my gradle.properties?

Correct 👍

@cortinico I can confirm that addListener callbacks are not firing on old arch too on 0.78 version. The idea is we have to see logs in dev tools with "scale anim value" + actual value. As you can see on 0.78 version on both arches we getting only logs for fadeAnim, but if you skim through repro app i did 2 subscriptions for fadeAnim value and for scaleAnim value. The only difference is that fadeAnim value is created via useAnimatedValue hook, and scale anim value created with Animated.add fn.

I'm trying to upload video within my post, but getting "failed to upload video" unfortunately. Will try to upload them tomorrow.

endlessqt avatar Feb 27 '25 18:02 endlessqt

Videos are named accordingly to testing environment.

https://github.com/user-attachments/assets/ef201010-6c36-40ad-b610-68e64db5e678

https://github.com/user-attachments/assets/be7c3e38-aa2e-4937-ac3e-e01db370d56d

https://github.com/user-attachments/assets/6ca67e8d-1569-4fc3-91c2-3ef91c62837a

endlessqt avatar Feb 27 '25 19:02 endlessqt

@cortinico Hey, any updates here? Did you find an owner?

endlessqt avatar Mar 04 '25 09:03 endlessqt

Up!

endlessqt avatar Mar 05 '25 15:03 endlessqt

@cortinico Should we invite someone else to push issue further? I guess there is no owner of issue right now

endlessqt avatar Mar 10 '25 11:03 endlessqt

Facing the same regression on 0.78 with interpolate. Listeners added via addListener are not firing anymore. The issue is quite easy to reproduce.

const App = () => {
  const scrollY = useAnimatedValue(0, { useNativeDriver: true });
  const interpolation = scrollY.interpolate({
    inputRange: [0, 100],
    outputRange: [0, 100],
    extrapolate: 'clamp',
  });
  useEffect(() => {
    const listenerId = interpolation.addListener(({value}) => {
      console.log(value); // ❌ never logged
    });
    return () => {
      interpolation.removeListener(listenerId);
    };
  }, [interpolation]);

  return (
    <Animated.ScrollView
      onScroll={Animated.event(
        [{ nativeEvent: { contentOffset: { y: scrollY } } }],
        { useNativeDriver: true },
      )}
    >
      <Animated.View
        style={{
          width: 20,
          height: 20,
          backgroundColor: 'black',
          transform: [ { translateX: interpolation } ],
        }}
      />
      {Array.from({ length: 100 }).map((_, index) => (
        <Text key={index}>Test</Text>
      ))}
    </Animated.ScrollView>
  );
};

CC @cortinico

SimpleCreations avatar Apr 22 '25 11:04 SimpleCreations

@cortinico is there a way to work around this while still using the new arch on 0.79.2?

gituser8796 avatar May 22 '25 10:05 gituser8796

Faced with this problem

Created a workaround by listening to both animated values

Bardiamist avatar Jun 18 '25 08:06 Bardiamist

@cortinico can you please confirm if there are any updates on this?

ManasGuptaSprinklr avatar Jun 24 '25 06:06 ManasGuptaSprinklr

Nope there are no updates

cortinico avatar Jun 24 '25 07:06 cortinico

I've found the commit that broke listeners on non-value animated nodes, here it is, shipped in 0.78: https://github.com/facebook/react-native/commit/38c46fe865305b67157e5088979584715aba3539#diff-2240566ab689dc07a5852b20181dc34135c94fec5ffccd810a4dcc12858627bd

After reverting it locally I've confirmed that the listeners work on 0.78 as they did on 0.77.

@yungsters do you have any additional info on why this change was necessary? I'm not very well familiar with RN internals, but I can try creating a PR bringing the listener logic back.

SimpleCreations avatar Aug 12 '25 14:08 SimpleCreations