Remove Item with animation in a Horizontal FlatList with LayoutAnimation in React Native

I have been working on a horizontal FlatList in React Native. The idea is, a user can remove the item by clicking on the item. So once the item is removed, I need to :

  • Remove the item from the list with a nice opacity animation
  • At the same time, I need to fill up space with the next items sliding in to fill it up properly.

At first, I was trying it out with react native Animated library but it was getting messier and I could not achieve the effects that I wanted. However, with LayoutAnimation from react-native, this can be done easily. Let’s start then. First, we will put the initial set up for our horizontal FlatList.

const { height, width } = Dimensions.get("window");
const dummyData = [
  {
    id: 1,
    name: "orange card",
    color: "orange",
  },
  {
    id: 2,
    name: "red card",
    color: "red",
  },
  {
    id: 3,
    name: "green card",
    color: "green",
  },
  {
    id: 4,
    name: "blue card",
    color: "blue",
  },
  {
    id: 5,
    name: "cyan card",
    color: "cyan",
  },
];
const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: "center",
    paddingTop: 120,
    backgroundColor: "#ecf0f1",
    padding: 8,
  },
  flatList: {
    paddingHorizontal: 16,
    paddingVertical: 16,
  },
  cardContainer: {
    height: 100,
    width: width * 0.5,
    marginRight: 8,
  },
  card: {
    height: 100,
    width: width * 0.5,
    borderRadius: 12,
    padding: 10,
  },
  text: { color: "white", fontWeight: 'bold' }
});

export default function App() {
  const [data, setData] = React.useState(dummyData);
  return (
    <View style={styles.container}>
      <FlatList
        showsHorizontalScrollIndicator={false}
        contentContainerStyle={styles.flatList}
        horizontal={true}
        data={data}
        keyExtractor={(item) => item.id.toString()}
        renderItem={({ item }) => {
          return (
            <TouchableOpacity
              style={styles.cardContainer}
              onPress={() => removeItem(item.id)}
            >
              <Card style={[styles.card, {backgroundColor: item.color}]}>
                <Text style={styles.text}>{item.name}</Text>
              </Card>
            </TouchableOpacity>
          );
        }}
      />
    </View>
  );
}

With this, we get the following output.

Our FlatList

Now it is time for removing the item from the FlatList, we can just pass the id of the item to our FlatList and remove the items that match the id. Like so:

const removeItem = (id) => {
    let arr = data.filter(function(item) {
      return item.id !== id
    })
    setData(arr);
  };

Now if we click our item, the items will be removed from the FlatList but without any animation. This will like odd. The output will be like the following –

removing item without animation

Okay, now let’s start the animation. With LayoutAnimation we can easily create a layout config that will have the effect.

const layoutAnimConfig = {
  duration: 300,
  update: {
    type: LayoutAnimation.Types.easeInEaseOut, 
  },
  delete: {
    duration: 100,
    type: LayoutAnimation.Types.easeInEaseOut,
    property: LayoutAnimation.Properties.opacity,
  },
};

const removeItem = (id) => {
   let arr = data.filter(function(item) {
     return item.id !== id
   })
   setData(arr);
   // after removing the item, we start animation
   LayoutAnimation.configureNext(layoutAnimConfig) 
};

If we check the config, we can see the animation that we are doing while deleting the item from the list. The type is easeInEaseOut and the property is opacity. So let us see the final result with LayoutAnimation effect.

remove item with animation

One last important thing to note that, make sure your keyExtractor returns a unique key otherwise the animation will not work. I was stuck with this for quite a long time. 😀

You can get the full source code in the following snack –

Comments

No comments yet. Why don’t you start the discussion?

Leave a Reply

Your email address will not be published. Required fields are marked *