Skip to content
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

Keyframe Animation only works with StyleSheet.create and within on Animated.View #2387

Closed
1 task done
EyMaddis opened this issue Aug 29, 2022 · 7 comments
Closed
1 task done
Labels
bug has: pr Subject of a pull request project:react-native-web Issue associated with react-native-web

Comments

@EyMaddis
Copy link

EyMaddis commented Aug 29, 2022

Is there an existing issue for this?

  • I have searched the existing issues

Describe the issue

(this might be too issues, but I guess that they are probably based on the same underlying problem)
Hi 👋

I recently upgraded from 0.11 to 0.18 and noticed that our loading indicators are broken (no longer animated). I noticed that the CSS property animationKeyframes is only respected if

  1. The element is a View (Animated.View does not work)
  2. The animation is passed through StyleSheet.create, inline styling does not work

The generated CSS contains all CSS animation properties (like animation-timing-function) except animation-name.

Expected behavior

Animation keyframes should be generated and work when using inline styles and/or Animated.View.
All Views should rotate in the provided test case.

Steps to reproduce

Use React Native Web 0.18.0. (See attached codesandbox)

const animation = {
  animationKeyframes: [
    {
      "0%": { transform: [{ rotate: "0deg" }] },
      "100%": { transform: [{ rotate: "360deg" }] }
    }
  ],
  animationDuration: "750ms",
  animationIterationCount: "infinite",
  animationTimingFunction: "linear",
  animationPlayState: "running"
};

const Styles = StyleSheet.create({
  animation
});

then render views

      <Animated.View
        style={[
          {
            width: 100,
            height: 100,
            backgroundColor: "red"
            //...animation
          }
        ]}
      >
        <Text>Animated.View inline!</Text>
      </Animated.View>
      <Animated.View
        style={[
          {
            width: 100,
            height: 100,
            backgroundColor: "red"
          },
          Styles.animation
        ]}
      >
        <Text>Animated.View StyleSheet!</Text>
      </Animated.View>
      <View
        style={[
          {
            width: 100,
            height: 100,
            backgroundColor: "green",
            ...animation
          }
        ]}
      >
        <Text>View inline!</Text>
      </View>
      <View
        style={[
          {
            width: 100,
            height: 100,
            backgroundColor: "green"
          },
          Styles.animation
        ]}
      >
        <Text>View StyleSheet!</Text>
      </View>

Observe that only the last View (with Text "View StyleSheet!") will start to rotate.

Test case

https://codesandbox.io/s/react-native-keyframe-animation-bug-ts4ib9

Additional comments

Thanks for being such a pillar of the React (Native) community!

@EyMaddis EyMaddis added the bug label Aug 29, 2022
@necolas
Copy link
Owner

necolas commented Aug 29, 2022

FWIW inline style animations haven't been supported for a long time. I'll look into why the Animated one doesn't work

@necolas
Copy link
Owner

necolas commented Aug 29, 2022

Oh it's because Animated calls StyleSheet.flatten which produces a new style object no longer recognized by the compiler (which doesn't produce class names at render time anymore, for React 18 reasons). You can consider Animated as only supporting inline styles at the moment. Is there a reason why you're trying to use CSS Animations with the Animated API, rather than using only one or the other?

@necolas
Copy link
Owner

necolas commented Aug 29, 2022

I might have a fix for this. I'll hopefully get a patch up soon for you to try in your environment

@necolas necolas added this to the 0.19: React 18 milestone Aug 29, 2022
@necolas necolas added the project:react-native-web Issue associated with react-native-web label Aug 29, 2022
necolas added a commit that referenced this issue Aug 29, 2022
Animated should now work with compiled and extracted styles. The
original styles are passed to components, rather than being flattened
into a new object that cannot be used by the style runtime to either
lookup the results of StyleSheet.create calls or consume extracted
styles. Inline styles that use AnimatedValue are moved into a seperate
object that is appended to the original styles.

Fix #2387
@EyMaddis
Copy link
Author

The reason for it was a single component for web and native, but using css animations on web and native Animated otherwise.
I could have done it differently but there was no reason for completely separate components.

Using Animated for the loading indicator was especially fragile as the indicator hides a lot of JS main thread work.

There is also a loading placeholder component that can get the opacity animated value from the parent, while also having an additional css animation that runs every time. I solved that by wrapping it into another Animated.View.

Is there a specific reason why inline animations are not supported? (I guess performance?)
I find it a bit weird that animation-name is just missing. Could there at least be a warning or is it hard to detect?

@necolas
Copy link
Owner

necolas commented Aug 29, 2022

I could have done it differently but there was no reason for completely separate components.

Why not use View for web and Animated.View for native? That seems like a relatively simple conditional that avoids the overhead of all the Animated implementation on web if you're not using it at all

Is there a specific reason why inline animations are not supported? (I guess performance?)

Because inline styles are not converted to CSS rules, but animations require CSS rules and keyframes.

@EyMaddis
Copy link
Author

Why not use View for web and Animated.View for native?

🤷‍♂️ Well, now I am since 0.18 😜

Thanks for the insight, makes sense!

@necolas necolas added the has: pr Subject of a pull request label Aug 30, 2022
necolas added a commit that referenced this issue Aug 30, 2022
Animated should now work with compiled and extracted styles. The
original styles are passed to components, rather than being flattened
into a new object that cannot be used by the style runtime to either
lookup the results of StyleSheet.create calls or consume extracted
styles. Inline styles that use AnimatedValue are moved into a seperate
object that is appended to the original styles.

Fix #2387
necolas added a commit that referenced this issue Sep 1, 2022
Animated should now work with compiled and extracted styles. The
original styles are passed to components, rather than being flattened
into a new object that cannot be used by the style runtime to either
lookup the results of StyleSheet.create calls or consume extracted
styles. Inline styles that use AnimatedValue are moved into a seperate
object that is appended to the original styles.

Fix #2387
necolas added a commit that referenced this issue Nov 28, 2022
Animated should now work with compiled and extracted styles. The
original styles are passed to components, rather than being flattened
into a new object that cannot be used by the style runtime to either
lookup the results of StyleSheet.create calls or consume extracted
styles. Inline styles that use AnimatedValue are moved into a seperate
object that is appended to the original styles.

Fix #2387
@EyMaddis
Copy link
Author

Awesome, you are the best, @necolas! 👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug has: pr Subject of a pull request project:react-native-web Issue associated with react-native-web
Projects
None yet
Development

No branches or pull requests

2 participants