react-native: VirtualizedList: You have a large list that is slow to update - make sure your renderItem function renders components that follow React performance best practices like PureComponent, shouldComponentUpdate, etc.

Please help, i have RN Application that fetch data to server paginately, every time scroll has end to bottom i call getMore function and get next offset to server then result of next offset i’ve been merged with list state

  1. On FlatList i’ve implement React PureComponent on Rendering ListItem but always have notice VirtualizedList: You have a large list that is slow to update - make sure your renderItem function renders components that follow React performance best practices like PureComponent, shouldComponentUpdate, etc.
  2. I’ve implement any other performance options but nothing change
  3. My data list scenario is fetching to api server that give partial or limit rows using cursor pagination by PRISMA JS, every i got EndReach bottom i call function getMore that will trigger to change cursor state and load more data from server then i merge that result on existing list

Expected Results

How i can remove that warning ?

`

const Tags = () => {
const navigation = useNavigation();
const mounted = useRef(false);
const [loader, setLoader] = useState(false);
const [cursor, setCursor] = useState(0);
const [list, setList] = useState([]);
const renderItem = ({item}) => <ListItem title={item.tag} />;

const getMore = () => {
    setCursor(list[list.length - 1].id);
};

useEffect(() => {
    mounted.current = true;

    const getList = async () => {
        try {
            setLoader(true);
            const data = await fetchList({cursor});
            setList(prevState => [...prevState, ...data]);
        } catch (error) {
            ToastAndroid.showWithGravity(error, 3000, ToastAndroid.BOTTOM);
        } finally {
            setTimeout(() => {
                if (mounted.current) {
                    setLoader(false);
                }
            }, 1000);
        }
    };

    getList();

    return () => {
      mounted.current = false;
    };
}, [cursor]);

  return (
    <View style={styles.container}>
      <FlatList
        refreshing={loader}
        data={list}
        renderItem={renderItem}
        keyExtractor={item => item.id}
        ListEmptyComponent={NoData}
        showsVerticalScrollIndicator={false}
        ListFooterComponent={loader ? <MoreLoader /> : null}
        ItemSeparatorComponent={ListSeparator}
        onEndReachedThreshold={0.5}
        onEndReached={getMore}
      />
      <AddButton />
    </View>
  );
};

// List Component
 class ListItem extends PureComponent {
    render() {
      const {title} = this.props;
      return (
        <Pressable style={styles.container} android_ripple={rippleConfig}>
          <View style={styles.listIconWrapper}>
            <AntIcon name="folder1" style={styles.listIcon} />
          </View>
          <View style={styles.listContentWrapper}>
            <Text numberOfLines={2} ellipsizeMode="tail">
              {title}
            </Text>
          </View>
        </Pressable>
      );
    }
  }

About this issue

  • Original URL
  • State: closed
  • Created 3 years ago
  • Reactions: 2
  • Comments: 21

Most upvoted comments

I face this issue when there’s an image inside my renderItem component even i’m using memo.

Any update on this? I face the same issue similarly.

const RenderCategoriesMenu = React.memo(({item}: {item: category}) => {
    return (
      <Menu.Item
        onPress={() => {}}
        title={item.categoryName}
        style={[
          styles.categoryItemContainer,
          {
            backgroundColor: colors.primary_light,
            borderColor: colors.primary_dark,
          },
        ]}
        titleStyle={[styles.categoryTitleStyle, {color: colors.text}]}
        contentStyle={styles.categoryItemContent}
      />
    );
  });
  • quite sure this function is not over re-render
  • warning does not show on comment/un-use this component, so the warning came from this component?
  • My list contains about 20+ items, no performance issue found

further looking back at my code, I found this component is defined inside another arrow function and it is the root cause of the warning. Each time, when the parent component renders, a new instance of this function is created, and that throws the warning (I thought).

Instead of that, I split the code out and call like this

const RenderCategoriesMenu = React.memo(({ item }) => {
  return <CategoryItem categoryName={item.categoryName} />;
});

and the warning’s gone. It’s been years for my case, but hope this may be helpful for anyone facing a situation like this

I solved this issue probably. The hint is official documents here. My example code is above. Finally, all of movements were so smoothly changed. In my case, I use React.memo and arePropsEqual(2nd parameter).

https://react.dev/reference/react/memo#reference

import { isSameDay } from 'date-fns';

...
const MemoList = React.memo(
  ({
    info,
    viewSize,
  }: {
    info: ListRenderItemInfo<Date>;
    viewSize: ViewSize;
  }) => <ListContainer itemInfo={info} viewSize={viewSize} />,
  (prevProps, nextProps) => isSameDay(prevProps.info.item, nextProps.info.item) // The type of item is Date.
);

<FlatList
    ...
    renderItem={(info: ListRenderItemInfo<Date>) => (
      <MemoList info={info} viewSize={viewSize} />
    )}
/>

Hi, i solved the problem with similar resolution using memo and give second parameter with (prevProps, nextProps) to be compared. here is my working code.

// this is where I solved the problem
const ProgramItem = memo(({ item }) => {
    const theme = useTheme();
    const navigation = useNavigation();
    return (
        <Pressable onPress={() => navigation.push("DetailProgram", { ...item })}>
            <Card style={{ ...styles.itemCard, backgroundColor: theme.colors.primary }}>
                <Card.Cover source={{ uri: item?.image }} style={styles.itemImage} />
                <Card.Content style={{ ...styles.itemContentWrapper, backgroundColor: theme.colors.primary }}>
                    <Text style={styles.itemTitle} numberOfLines={1} ellipsizeMode='tail'>{item?.title}</Text>
                    <Text style={styles.itemContent} numberOfLines={3} ellipsizeMode='tail'>{item?.content}</Text>
                </Card.Content>
            </Card>
        </Pressable>
    );
}, (prevProps, nextProps) => { // and here is what i didn't notice before.
    return prevProps.item === nextProps.item;
});

const ProgramList = () => {
    const [data, setData] = useState([]);
    const [loading, setLoading] = useState(true);
    const controller = useRef(new AbortController());

    const getData = async () => {
        try {
            const { signal } = controller.current;
            const res = await fetch(`https://jsonplaceholder.org/posts`);
            const list = await res.json();

            if (!signal.aborted) {
                setData(list);
                setLoading(false);
            }
        } catch (error) {
            if (!controller.current.signal.aborted) {
                if (process.env.NODE_ENV !== "production") {
                    console.log(error);
                }
            }
        }
    }

    useEffect(() => {
        getData();

        return () => {
            controller.current.abort();
        }
    }, []);

    return (
        <>
            <View style={styles.sectionTitleWrapper}>
                <Text style={styles.sectionTitle}>Program Unggulan</Text>
            </View>
            {loading ? (
                <View style={{ flexDirection: 'row', paddingHorizontal: 8 }}>
                    {[1, 2].map(item => (
                        <ShimmerPlaceHolder
                            key={item}
                            style={{ height: 280, width: 310, margin: 8, borderRadius: 8 }}
                        />
                    ))}
                </View>
            ) : (
                <FlatList
                    data={data}
                    keyExtractor={(item) => item?.id.toString()} // Corrected keyExtractor
                    horizontal
                    renderItem={({ item }) => <ProgramItem item={item} />}
                    contentContainerStyle={{ paddingHorizontal: 8 }}
                />
            )}
        </>
    )
}

I solved this issue probably. The hint is official documents here. My example code is above. Finally, all of movements were so smoothly changed. In my case, I use React.memo and arePropsEqual(2nd parameter).

https://react.dev/reference/react/memo#reference

import { isSameDay } from 'date-fns';

...
const MemoList = React.memo(
  ({
    info,
    viewSize,
  }: {
    info: ListRenderItemInfo<Date>;
    viewSize: ViewSize;
  }) => <ListContainer itemInfo={info} viewSize={viewSize} />,
  (prevProps, nextProps) => isSameDay(prevProps.info.item, nextProps.info.item) // The type of item is Date.
);

<FlatList
    ...
    renderItem={(info: ListRenderItemInfo<Date>) => (
      <MemoList info={info} viewSize={viewSize} />
    )}
/>

can u explain code

I face this issue when there’s an image inside my renderItem component even i’m using memo.

Same here