Skip to main content

Layout Animation

There are two ways to animate your UI in React Native: you can either define the exact animation yourself, or you can let LayoutAnimation do all the work for you.

LayoutAnimation is incredibly powerful, although not very flexible. It works by somewhat magically animation the next UI update from after it's triggered, using the given animation configuration. The downside is that other than configuring the speed of the animation, you'll have no control over it. You can't choose to animate just part of the screen. So in most cases you'll end up building your own custom animations without LayoutAnimation. It's a whole lot better than no animation at all though, so it can be nice to use that instead of a fine grained animation as a first pass.

Add delete mood functionality#

First open App.provider.tsx and expose a function that lets you delete a given mood:

src/App.provider.tsx
const handleDeleteMood = React.useCallback((mood: MoodOptionWithTimestamp) => {  setMoodList((current) => {    const newValue = current.filter(      (item) => item.timestamp !== mood.timestamp    );    setAppData({ moods: newValue });    return newValue;  });}, []);

Now in MoodItemRow, add a "delete" button that calls this function via context:

src/components/MoodItemRow.tsx
import { Pressable } from 'react-native';import { useAppContext } from '../App.provider';
const appContext = useAppContext();
---
<Pressable hitSlop={16} onPress={() => appContext.handleDeleteMood(item)}>  <Text style={styles.deleteText}>Delete</Text></Pressable>;
---
deleteText: {  color: theme.colorBlue,  fontFamily: theme.fontFamilyLight,},

Animate the list when an item gets removed#

LayoutAnimation is enabled by default on iOS, but it's still experimental on Android. In order to enable LayoutAnimation on Android, open App.tsx and add the following:

src/App.tsx
import { Platform, UIManager } from 'react-native';
if (Platform.OS === 'android') {  if (UIManager.setLayoutAnimationEnabledExperimental) {    UIManager.setLayoutAnimationEnabledExperimental(true);  }}

Now to animate the list, open MoodItemRow and

  1. pull the onPress function out to a callback
  2. call LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut); before the delete function

Note - it actually doesn't matter whether you put the LayoutAnimation.configureNext call before or after the handleDeleteMood call. It will always apply to the next UI update.

src/components/MoodItemRow.tsx
const handlePress = React.useCallback(() => {  LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut);  appContext.handleDeleteMood(item);}, [appContext, item]);

Finally you might have noticed that when adding new mood items, new rows get added to the bottom of our list, not the top. In this case it would make more sense for the new entries to be added to the top instead. Thankfully we can easily fix this:

Open History.screen and call slice().reverse() on the mood list before mapping over it:

src/screens/History.screen.tsx
-      {appContext.moodList.map(item => (+      {appContext.moodList.slice().reverse().map(item => (
danger

Remember reverse() alone mutates the original array which can cause unintended consequences.

This is why we call slice() on the array first to create a copy of it.