user9086883
user9086883

Reputation: 25

React Native SectionList performance issue

I have a json object like this that coming from our api:

{
  "data": {
    "items": [
      {
        "id": 1646,
        "created_at": "2021-12-10T17:47:25+00:00",
      },
      {
        "id": 1640,
        "created_at": "2021-12-10T13:23:49+00:00",
      },
      {
        "id": 1610,
        "created_at": "2021-12-10T09:44:55+00:00",
      },
      {
        "id": 1609,
        "created_at": "2021-12-10T09:44:19+00:00",
      },
      {
        "id": 1608,
        "created_at": "2021-12-10T09:43:46+00:00",
      },
      {
        "id": 1607,
        "created_at": "2021-12-10T09:43:07+00:00",
      },
      {
        "id": 1606,
        "created_at": "2021-12-10T09:42:31+00:00",
      },
      {
        "id": 1605,
        "created_at": "2021-12-10T09:41:52+00:00",
      },
      {
        "id": 1604,
        "created_at": "2021-12-10T09:41:13+00:00",
      },
      {
        "id": 1601,
        "created_at": "2021-12-09T18:09:15+00:00",
      },
      {
        "id": 1600,
        "created_at": "2021-12-09T18:08:45+00:00",
      },
      {
        "id": 1599,
        "created_at": "2021-12-09T18:08:21+00:00",
      },
      {
        "id": 1598,
        "created_at": "2021-12-09T18:07:48+00:00",
      },
      {
        "id": 1594,
        "created_at": "2021-12-09T17:19:54+00:00",
      },
      {
        "id": 1591,
        "created_at": "2021-12-09T16:39:10+00:00",
      }
    ],
    "page": 1,
    "total": 71,
    "pages": 5,
    "perPage": 15
  }
}

and I have grouped them by date with this function:

export const createGroups = (data: any, dateField: string) => {
  const groups = data?.reduce((grp: any, bundle: any) => {
    const date = bundle[dateField]?.split('T')[0];

    if (!grp[date]) {
      grp[date] = [];
    }
    grp[date].push(bundle);
    return grp;
  }, {});
  let groupArrays = {};
  if (groups) {
    groupArrays = Object.keys(groups).map(date => {
      return {
        date,
        data: groups[date],
      };
    });
  }
  return groupArrays;
};

that returns this grouped array:

[
  {
    "date": "2021-12-10",
    "data": [
      {
        "id": 1646,
        "created_at": "2021-12-10T17:47:25+00:00"
      },
      {
        "id": 1640,
        "created_at": "2021-12-10T13:23:49+00:00"
      },
      {
        "id": 1610,
        "created_at": "2021-12-10T09:44:55+00:00"
      },
      {
        "id": 1609,
        "created_at": "2021-12-10T09:44:19+00:00"
      },
      {
        "id": 1608,
        "created_at": "2021-12-10T09:43:46+00:00"
      },
      {
        "id": 1607,
        "created_at": "2021-12-10T09:43:07+00:00"
      },
      {
        "id": 1606,
        "created_at": "2021-12-10T09:42:31+00:00"
      },
      {
        "id": 1605,
        "created_at": "2021-12-10T09:41:52+00:00"
      },
      {
        "id": 1604,
        "created_at": "2021-12-10T09:41:13+00:00"
      }
    ]
  },
  {
    "date": "2021-12-09",
    "data": [
      {
        "id": 1601,
        "created_at": "2021-12-09T18:09:15+00:00"
      },
      {
        "id": 1600,
        "created_at": "2021-12-09T18:08:45+00:00"
      },
      {
        "id": 1599,
        "created_at": "2021-12-09T18:08:21+00:00"
      },
      {
        "id": 1598,
        "created_at": "2021-12-09T18:07:48+00:00"
      },
      {
        "id": 1594,
        "created_at": "2021-12-09T17:19:54+00:00"
      },
      {
        "id": 1591,
        "created_at": "2021-12-09T16:39:10+00:00"
      }
    ]
  }
]

and this is my Screen with SectionList in it:

import React, { useState } from 'react';
import { VStack, SectionList, Text, HStack, Center } from 'native-base';
import moment from 'moment';
import { useGetAllTransactions } from '../hooks';
import { translate } from '@locale';
import { TransactionCard } from '../components';
import { ActivityIndicator, SectionListData } from 'react-native';
import { createGroups } from 'lib/bundle';
import { Transaction } from 'models/order/transaction';

type GroupedTransaction = {
  title: string;
  data: Transaction[];
};

export default function EarningListScreen() {
  const {
    data,
    isLoading,
    hasNextPage,
    isFetchingNextPage,
    refetch,
    fetchNextPage,
  } = useGetAllTransactions();

  const [transactions, setTransactions] = useState<GroupedTransaction[]>([]);

  React.useEffect(() => {
    if (data?.items) {
      const bundle = createGroups(
        data.items,
        'created_at',
      ) as GroupedTransaction[];
      setTransactions(bundle);
    }
  }, [data]);

  const renderItem = ({ item }: { item: Transaction }) => {
    return (
      <TransactionCard>
          <TransactionCard.Item
            flex={3}
            label={translate('earnings.list.datetime')}
            text={moment(item.created_at).format('ddd, MMM DD HH:mm')}
          />
      </TransactionCard>
    );
  };

  const renderHeader = (item: {
    section: SectionListData<
      Transaction,
      { date: string; data: Transaction[] }
    >;
  }) => (
    <HStack>
      <Text fontWeight="bold">
        {moment(item.section.date).format('MMM YYYY ')}
      </Text>
    </HStack>
  );

  return (
    <VStack>
      <SectionList
        contentContainerStyle={{ flexGrow: 1 }}
        flexGrow={1}
        sections={transactions}
        keyExtractor={(item, index) => (item.id + index).toString()}
        renderItem={renderItem}
        renderSectionHeader={renderHeader}
        refreshing={isLoading}
        onRefresh={refetch}
        onEndReachedThreshold={0.5}
        onEndReached={() =>
          hasNextPage && !isFetchingNextPage && fetchNextPage()
        }
        ListEmptyComponent={() => null}
        showsVerticalScrollIndicator={false}
      />
    </VStack>
  );
}

but the SectionList has performance issue. I think my createGroups function has some issue and I don't why and how can I handle that.

Upvotes: 0

Views: 1286

Answers (2)

Venkata Krishna
Venkata Krishna

Reputation: 1

  1. I also faced the same issue. Keep logs in render item and check how many times logs are printing.

  2. Then wrap the render item with React.memo initially (keep the render item in separate component) it will avoid unnecessary re-rendering and check the logs.

  3. Then work around further with useMemo and useCallback it will improve more

Upvotes: 0

corasphinx
corasphinx

Reputation: 63

const renderItem = ({ item }: { item: Transaction }) => {
    return (
      <TransactionCard>
          <TransactionCard.Item
            flex={3}
            label={translate('earnings.list.datetime')}
            text={moment(item.created_at).format('ddd, MMM DD HH:mm')}
          />
      </TransactionCard>
    );
  };

You need to add the key props in

Upvotes: 0

Related Questions