nandorojo / moti

🐼 The React Native (+ Web) animation library, powered by Reanimated 3.
https://moti.fyi
MIT License
3.91k stars 120 forks source link

MotiView blinks on first state change #177

Closed astware closed 2 years ago

astware commented 2 years ago

Hi Fernando! First of all, great job on this library, I immediately fell in love with it.

I'm having an issue when using transforms on entry animations. When I mount my view it slides from the bottom with a "translateY" transform, and it works perfectly, however, the first time the local state changes, there is a small flicker or blink in the component.

I've attached a video showing the issue below.

https://user-images.githubusercontent.com/77419324/156472693-03ebb961-19d7-4202-af5a-8c3bc3a860d6.MP4

This is the code

import React, {useState} from 'react'
import {StyleSheet, Text, TouchableOpacity, View} from 'react-native';
import {COLOR_BACKGROUND} from "../config/colors";
import {SPACING} from "../config/layout";
import {MotiView} from 'moti';
import {elevationShadowStyle} from "../helpers/elevationShadowStyle";

const DemoScreen = () =>{

    const [value, setValue] = useState(false);

    const handlePress = () => {
        setValue(true);
    };

    return <View style={styles.container}>
        <TouchableOpacity onPress={handlePress} style={styles.button}>
            <Text>Click</Text>
        </TouchableOpacity>
        <MotiView
            from={{
                transform: [
                    {
                        translateY: 100,
                    },
                ],
            }}
            animate={{
                transform: [{ translateY: 0 }],
            }}
        >
            <View style={styles.fixedBottomContainer}>
                <Text>I flicker on the first button click.</Text>
            </View>
        </MotiView>
    </View>
};

const styles = StyleSheet.create({
    container: {
        padding: 20,
        backgroundColor: COLOR_BACKGROUND
    },
    divider: {
        marginVertical: 10
    },
    button: {
        backgroundColor: 'red',
        padding: SPACING * 2,
        marginBottom: SPACING * 3
    },
    fixedBottomContainer: {
        padding: SPACING * 2,
        backgroundColor: 'white',
        ...elevationShadowStyle(20)
    }
});

export default DemoScreen;

When "handlePress" is called the first time and "value" gets updated, the flicker happens.

I hope it's just a mistake in my code.

Greetings from México!

nandorojo commented 2 years ago

Hmm weird, could you try it on Expo Snack?

nandorojo commented 2 years ago

also what are all the versions you’re using of things?

astware commented 2 years ago

also what are all the versions you’re using of things?

This are my relevant package.json dependencies:


"dependencies": {
    "expo": "~44.0.0",
    "expo-app-loading": "~1.3.0",
    "expo-asset": "~8.4.6",
    "expo-constants": "~13.0.2",
    "expo-device": "~4.1.1",
    "expo-font": "~10.0.5",
    "expo-status-bar": "~1.2.0",
    "moti": "^0.17.1",
    "react": "17.0.1",
    "react-dom": "17.0.1",
    "react-native": "0.64.3",
    "react-native-gesture-handler": "^2.2.0",
    "react-native-reanimated": "~2.3.1",
  }

I'll try to set the Expo Snack, but I'm using Expo 44 and it doesn't seem to be available in Expo Snack.

nandorojo commented 2 years ago

maybe see what happens with sdk 43? would help to have a reproduction for me

astware commented 2 years ago

With this dependencies is working as expected, so the issue is dependency-related. I added the snack at the end of this comment.


{
  "dependencies": {
    "moti": "^0.17.1",
    "expo-constants": "~12.1.3",
    "@expo/vector-icons": "^12.0.0",
    "react-native-paper": "4.9.2",
    "react-native-screens": "~3.8.0",
    "react-native-reanimated": "~2.2.0",
    "react-native-gesture-handler": "~1.10.2"
  }
}

Heres the Snack: https://snack.expo.dev/@astware/motiview-flicker-issue

nandorojo commented 2 years ago

looks like the issue is reanimated 2.3.1 then. what about 2.3.2 or 2.4?

astware commented 2 years ago

Hmm... neither are solving the issue. I'll try more versions tomorrow.

nandorojo commented 2 years ago

try yarn why react-native-reanimated? are you doing this in a blank app btw? be sure to rebuild the dev client when you change versions. since it both works and breaks with the same moti version, I would guess it isn’t moti.

astware commented 2 years ago

Hi Fernando, thank you so much for your time and support.

I did try the code in a blank app with the same results, from reanimated 2.3.0 and upwards the error persisted.

I had to downgrade expo to SDK version 43.0.5 (from 44.0.0) and use Moti with reanimated 2.2.0.

This way it works like in the snack. Since I don't really need Expo 44's features this is fine for me.

lklima commented 2 years ago

I faced this same problem, I solved it by setting the initial value in the state. for some reason on first state changes it seems that the component is rendered by flickering between the from and animate value

export default function Star({ stars }: Props) {
  const [scale, setScale] = useState(0);

  useEffect(() => {
    setTimeout(() => setScale(1), 1000);
  }, []);

  return (
    <MotiView
      delay={2000}
      from={{ scale }}
      animate={{ scale: 1 }}
      transition={{ type: "timing" }}
    />
  );
}
nandorojo commented 2 years ago

for this case, it might make more sense to just memoize it. i’m curious if this happens with reanimated 2.4.x

nandorojo commented 2 years ago

@lklima what if you did this?

export default function Star({ stars }: Props) {
  return useMemo(() => (
    <MotiView
      delay={2000}
      from={{ scale: 0 }}
      animate={{ scale: 1 }}
      transition={{ type: "timing" }}
    />
  ), [])
}
lklima commented 2 years ago

@nandorojo i already tried with useMemo , it didn't work, this appears to be a reanimated bug. I can’t try 2.4.x due to expo managed limitation.

nandorojo commented 2 years ago

if you use expo dev clients you can try 2.4.

alternatively, can you see if it works with useAnimationState from Moti, instead of from/animate props?

lklima commented 2 years ago

@nandorojo i forgot to mention i tried with useAnimationState and on first state updated it returns to initial shared value and stuck. I'm not using expo dev client. I just realised that this issue only occurs with transform styles like scale or translate. same in the @astware code.

this is my project if want check it out https://github.com/lklima/gnome

nandorojo commented 2 years ago

can you link to the actual file in the project

lklima commented 2 years ago

this https://github.com/lklima/gnome/blob/master/src/screens/Main/components/BottomContent/index.tsx and this: https://github.com/lklima/gnome/blob/master/src/screens/Main/components/Star/index.tsx

alantoa commented 2 years ago

Hi, @astware @lklima Upgrade you react-native-reanimated version to v2.5.0+, will be resolved! You can check out this PR https://github.com/software-mansion/react-native-reanimated/pull/2851.

By the way, @nandorojo thanks a lot for your library, Moti let's write a lot less animation code, It's grate!

nandorojo commented 2 years ago

sweet! thanks for the update, and glad it’s useful @alantoa