Layout animation leave orphaned component in Expo
See original GitHub issueDescription
I found a strange behavior while trying to use react-native-reanimated layout animation with the latest Expo SDK (44). Component with layout animation seems to leave orphaned component at re-render. (related expo issue)
I have a simple conditional rendering, when the component mount it should display a spinner for 3000ms and then a list of (transparent for demo purpose) items. However, on the first render after the 3000ms the spinner AND the list are both visible at the same time.
If I reload the project everything works as expect. But as soon as I completely restart the app, this behavior happen.
I was able to reproduce this behavior in a fresh new app, I will include the steps bellow.
Expected behavior
The layout animation works as expected (and are, actually, awesome). But it seems to introduce a bug with conditional component rendering. In my case, after 3000ms, the spinner is supposed to be hidden and replaced by the list.
Actual behavior & steps to reproduce
At component mount a spinner is supposed to be visible during 3000ms. After this time, the spinner should be replaced by a scrollview.
Check my minimal code bellow.
Snack or minimal code example
// update to expo 44 (currently beta) to be able to use react-native-reanimated > 2
$ EXPO_BETA=1 expo init --npm
$ # Choose "blank (TypeScript)"
$ expo install react-native-reanimated react-native-screens
babel.config.js
module.exports = function (api) {
api.cache(true);
return {
presets: ['babel-preset-expo'],
plugins: ['react-native-reanimated/plugin'],
};
};
App.tsx
import { useEffect, useState } from 'react';
import { ActivityIndicator, StyleSheet, Text, View } from 'react-native';
import Animated, {
FadeInUp,
FadeOutDown,
Layout,
} from 'react-native-reanimated';
const AnimatedView = Animated.createAnimatedComponent(View);
export default function App() {
const [isLoading, setIsLoading] = useState<boolean>(true);
useEffect(() => {
const timeout = setTimeout(() => setIsLoading(false), 3000);
return () => {
clearTimeout(timeout);
};
}, []);
return (
<View style={styles.container}>
{isLoading ? (
<ActivityIndicator size='large' color='red' />
) : (
<AnimatedView
entering={FadeInUp}
exiting={FadeOutDown}
layout={Layout.springify()}
style={styles.scrollContainer}
>
{[...Array(10).keys()].map((value) => (
<View style={styles.row} key={value}>
<Text>row n°{value}</Text>
</View>
))}
</AnimatedView>
)}
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
scrollContainer: {
flex: 1,
width: '100%',
},
row: {
flexDirection: 'row',
backgroundColor: 'transparent',
height: 50,
},
});
Package versions
"expo": "~44.0.0",
"react-native": "0.64.3",
"react-native-reanimated": "~2.3.1",
"react-native-screens": "~3.10.1"
Node.js: v14.15.3
Affected platforms
- Android : (not sure, unable to test at the moment)
- iOS
Issue Analytics
- State:
- Created 2 years ago
- Comments:11

Top Related StackOverflow Question
Calling
enableLayoutAnimations(true)inApp.tsxfixes this for me:Also made a repo of the project detailed above ^ for ease of debugging: https://github.com/bryansum/reanimated-layout-repro
Would be interesting to see if this fixes things for anyone else.
Thanks for reporting this issue man! I am facing same bug in my app
Overlapping on condition render and it goes if I manually refresh