简体   繁体   中英

FlatList is re-rendering items everytime screen is scrolled

I have a list of 300 items. I'm using FlatList to render the items.

ISSUE:

  • List items re-rendering when I scroll the screen. Even when I have wrapped the component in React.memo.

I tried to optimise the list by tweaking the windowSize , maxToRenderPerBatch but the issue still persist.

You can check the code in below sandbox link.

Thankyou in advance !

https://codesandbox.io/s/gracious-dhawan-i4d51h?file=/src/App.js

Below is the code snippet

const data = [
{
    id: 1,
    first_name: "Shaina",
    last_name: "Osorio",
    email: "sosorio0@a8.net"
  },
  {
    id: 2,
    first_name: "Ania",
    last_name: "Cotilard",
    email: "acotilard1@about.me"
  },
  {
    id: 3,
    first_name: "Hagen",
    last_name: "Lisciandri",
    email: "hlisciandri2@nature.com"
  }
]

 const isEqual = (prev, next) => { return true; }; const RenderItem = React.memo((props) => { const { id, first_name, email } = props; console.log("id >>> ", id); return ( <View style={{ padding: 5, backgroundColor: "lightblue", marginVertical: 3 }} > <Text>First Name: {first_name}</Text> <Text>Email: {email}</Text> </View> ); }, isEqual); function App() { return ( <View style={{ flex: 1 }}> <FlatList data={data} renderItem={({ item }) => ( <RenderItem id={item.id} first_name={item.first_name} email={item.email} /> )} initialNumToRender={15} maxToRenderPerBatch={15} keyExtractor={(item) => item.id} /> </View> ); } export default App;

In your example, you are logging inside your renderItem, so when a new element comes into the rendered area, it is logged. This happens when you scroll. But this doesn't mean that the whole list will be re-rendered. Just place a conosle.log directly in the component that hosts the list, and you'll see that it's only rendered once, unlike the renderItem, which is rendered every time a new item is created by a scroll.

const App = ()=> {
  console.log("Entire List Rerendered");
  return (
    <View style={{ flex: 1 }}>
      <FlatList
        data={data}
        renderItem={rendering}
        initialNumToRender={5}
        maxToRenderPerBatch={5}
        keyExtractor={(item) => item.id}
      />
    </View>
  );
}

Flashlist might help, because it recycles renderItems and doesn't destroy them like Flatlist does. But you should test that better.

Can you define it as a separate function

const rendering = ({ item }) => {
  return (
    <RenderItem
      id={item.id}
      first_name={item.first_name}
      email={item.email}
    />
  )
}

and then call it on your flat list?

<FlatList
  data={data}
  renderItem={rendering}
  initialNumToRender={15}
  maxToRenderPerBatch={15}
  keyExtractor={(item) => item.id}
/>

Inline event handlers are anonymous functions. They are created every time the component renders.

UPDATE

Extract your render and keyExtractor functions and surround them with useCallback like that

function App() {
  const rendering = useCallback(({item}) => {
    console.log("id >>> ", item.id);
    return (
      <View
      style={{
        padding: 5,
        backgroundColor: "lightblue",
        marginVertical: 3
      }}
    >
      <Text>First Name : {item.first_name}</Text>
      <Text>Email : {item.email}</Text>
    </View>
    )
  }, []);

  const keyExtractoring = useCallback((item) => {
    return item.id.toString();
  }, []);

  return (
    <View style={{ flex: 1 }}>
      <FlatList
        data={data}
        renderItem={rendering}
        initialNumToRender={5}
        maxToRenderPerBatch={5}
        keyExtractor={keyExtractoring}
      />
    </View>
  );
}

Updated fiddle

Check out FlashList by Shopify they are saying that it is much more optimized than Flatlist. maybe it can meet your needs. no harm in trying: Click Here

    import React from "react";
    import { View, Text, StatusBar } from "react-native";
    import { FlashList } from "@shopify/flash-list";
    
    const DATA = [
      {
        title: "First Item",
      },
      {
        title: "Second Item",
      },
    ];
    
    const MyList = () => {
      return (
        <FlashList
          data={DATA}
          renderItem={({ item }) => <Text>{item.title}</Text>}
          estimatedItemSize={200}
        />
      );
    };

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM