VirtualizedList: You have a large list that is slow to update

前端 未结 4 1221
暖寄归人
暖寄归人 2020-12-05 02:10

I use FlatList with large number of items. I get following alert from Expo XDE.

VirtualizedList: You have a large list that is slow to update - make

相关标签:
4条回答
  • 2020-12-05 02:27

    I was previously seeing this error. After optimizing my code, I no longer see it. I figured out the problem by adding console.log() statement to the render() function of the Component that creates the FlatList, and the function that renders each item in the List. I noticed that my code was previously re-rendering the entire FlatList and all its items whenever there's a state change to any component on that page (even a component that's not related to the FlatList). I fixed this by converting various components to PureComponents. Here's what my FlatList declaration looks like:

    <FlatList
        ref={(ref) => { this.flatListRef = ref; }}
        data={allPosts}
        initialNumToRender={7}
        renderItem={({ item }) =>
          <Post postJson={item} isGroupAdmin={isGroupAdmin} user={user} />
        }
      />
    

    Notice that I'm returning <Post /> which is a pure component:

    import React, { PureComponent } from 'react';
    class Post extends PureComponent {
    
      render() { ... }
    }
    

    This ensures that the FlatList re-renders a only if the post changes. When I was previously passing a normal function to renderItem i.e., a function that does something like this:

    return (
      <View>
      ...
      </View>
    );
    

    I noticed that the FlatList was re-rendering all items whenever any item changed. Now, by using a PureComponent, the FlatList only renders the new item added to the list (if the list is already being displayed).

    It still takes relative long to render the entire list the first time. However, initialNumToRender ensures that the screen is filled up pretty much instantaneously (while the remain items get rendered in the background). And more importantly, after that initial rendering, the FlatList only ever has to render one item at a time (the item that changes).

    I found this post very helpful).

    I've just realized this is also explained here

    0 讨论(0)
  • 2020-12-05 02:35

    I noticed that the answer to this question dosen't proffer solution for those using functional component and hooks. I encountered this problem and i was able to get rid of it by using the hook "useMemo()"

    <FlatList
                    keyExtractor={keyExtractor}
                    data={productsState.products}
                    renderItem={renderItem}
                />
    const renderItem = ({ item }) => (
                <ListItem
                    title={item.ProductName}
                    subtitle={(item.ProductQuantity) + " " + (item.QuantityType !== 
                    null ? item.QuantityType : " ") }
                    bottomDivider
                    topDivider
                    chevron
                    checkmark={checkMark}
                    onLongPress={() => setCheckMark(!checkMark)}
                    rightSubtitle={(item.Currency !== null ? item.Currency: " " ) + 
                    " " + (item.productCost !== null ? item.productCost: " " )}
                    rightSubtitleStyle={{ marginTop: -20 }}
                    badge={{ value: item.sellingPrice, textStyle: { color: 'orange' }, containerStyle: { marginTop: -20 } }}
                />
            )
    

    The renderItem function is an expensive computation, because it a long list to render. Instead I memoize it as follows

                const memoizedValue = useMemo(() => renderItem, [productsState.product]);
    
    <FlatList
                    keyExtractor={keyExtractor}
                    data={productsState.products}
                    renderItem={memoizedValue}
                />
    const renderItem = ({ item }) => (
            <ListItem
                title={item.ProductName}
                subtitle={(item.ProductQuantity) + " " + (item.QuantityType !== 
                null ? item.QuantityType : " ") }
                bottomDivider
                topDivider
                chevron
                checkmark={checkMark}
                onLongPress={() => setCheckMark(!checkMark)}
                rightSubtitle={(item.Currency !== null ? item.Currency: " " ) + 
                " " + (item.productCost !== null ? item.productCost: " " )}
                rightSubtitleStyle={{ marginTop: -20 }}
                badge={{ value: item.sellingPrice, textStyle: { color: 'orange' }, containerStyle: { marginTop: -20 } }}
            />
        )
    

    Don't forget to import useMemo from react, inorder to make this work.

    Good Luck!

    0 讨论(0)
  • 2020-12-05 02:37

    Also make sure, you don't encapsulate FlatList with SourceList. For me it accidentally appears, because I used native-base, and didn't noticed, that their Component <Content> replace ScrollList.

    For more Information see here: https://stackoverflow.com/a/54512633/1256697

    0 讨论(0)
  • 2020-12-05 02:42

    I figured it out, why this bug is happened. The main problem is, when your onEndReached event is happened, im sure you are loading something from server, which means, you need to wait until your loading is finished from server, so after that you can call onEndReached event.

    But in your case there is multilple calling of onEndReached event. So when it happens, your application was trying to load datas from server again and again.

    Ok, how to solve this problem: you need to create new state, for example this is realization of infinite scrolling by pagination.

    const [loader, setLoader] = useState<boolean>(false);
    
    const onEndReached = (page) => {
      if (next && !loader) {
        setPage(page + 1)
      }
    }
    
    const loadData = async () => {
      setLoader(true);
      const resp = await getData();
      setLoader(false);
    }
    
    <FlatList ...someprops onEndReached={onEndReached} />
    
    0 讨论(0)
提交回复
热议问题