nandorojo / moti

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

How to use <Skeleton> with Flatlist? #250

Closed ansh closed 1 year ago

ansh commented 1 year ago

Is there an existing issue for this?

Current Behavior

Right now, if you have a FlatList, and wrap the whole thing with a Skeleton, the loader shows one small square since the FlatList data has not yet bee fulfilled.

However, if you wrap individual items (inside renderItem) with Skeleton, it doesn't work as the data is not loaded so the FlatList shows the empty component while loading is happening.

Expected Behavior

A simple way to wrap a FlatList renderItem or whole FlatList and have Skeleton loading.

Steps To Reproduce

No response

Versions

- Moti: 0.21.1
- Reanimated: 2.12.0
- React Native: 0.70.5
- Expo SDk: v47

Screenshots

No response

Reproduction

import * as React from 'react';
import { Text, View, StyleSheet, FlatList } from 'react-native';
import Constants from 'expo-constants';

import { Skeleton } from "@motify/skeleton";

const LOADED_DATA = [
  {
    name: "Person 1",
    friends: "54"
  },
    {
    name: "Person 2",
    friends: "21"
  },
    {
    name: "Person 3",
    friends: "53"
  },
    {
    name: "Person 4",
    friends: "78"
  },
    {
    name: "Person 5",
    friends: "12"
  }
]
export default function App() {
  const [data, setData] = React.useState([]);

  React.useEffect(() => {
    setTimeout(() => {
      setData(LOADED_DATA);
    }, 2000)
  }, [])

  return (
    <View style={styles.container}>
      <Skeleton>
      {!!data ? <FlatList
        data={data}
        renderItem={({item, index}) => {
          return (
            <View style={{flexDirection: "row", justifyContent: "space-between", marginVertical: 20}}>
            <Text>{item.name}</Text>
            <Text>{item.friends}</Text>
            </View>
          )
        }}
        ListEmptyComponent={<Text>This list is empty!</Text>}
       /> : null}
       </Skeleton>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    paddingTop: Constants.statusBarHeight,
    backgroundColor: '#ecf0f1',
    padding: 8,
  },
});
nandorojo commented 1 year ago

This is expected behavior. Check out my article about skeletons and how to use them with lists:

https://dev.to/nandotherojo/stop-using-loading-spinners-pkh

ansh commented 1 year ago

The example that you gave in the article will work if the component is defined to handle the loading state. In my case, the renderItem lives inside the same file as the FlatList, allowing such a structure to not be possible as I cannot call that component. I guess I can refactor my code and I understand that solving for every use-case might be outside the scope of this library.

Thanks! I'll close this now.

nandorojo commented 1 year ago

It would be pretty easy to use with FlatList too. The article gives the idea you’d need. You could just render a different FlatList if data is undefined with an array of numbers as its data prop.

ansh commented 1 year ago

Yes, that is what I am doing. Definitely more code than your original example so was hoping for something like that, but this is amazing too. ;)

nandorojo commented 1 year ago

You could also just use my loading example without a flatlist for the loading state. It isn’t necessary to scroll a skeleton.

ansh commented 1 year ago

Yes, both work! Thank you :) However, now I am facing another issue #251