Состояние обновления, когда список разделов завершен рендеринг

#react-native

#react-native

Вопрос:

У меня есть sectionlist с ActivityIndicator в нижнем колонтитуле. ActivityIndicator не исчезает даже после того, как список отобразил каждый элемент. Данные являются локальными данными.

Я знаю, что мне нужно использовать React Hook, поэтому я создал _handleLoadMore() для обновления состояния, но я не знаю, как определить, когда список подходит к концу.

Это мой код

 import React, {useState, useEffect} from 'react';
import {
  View,
  Text,
  StyleSheet,
  SectionList,
  ActivityIndicator,
} from 'react-native';
import {SafeAreaView} from 'react-native-safe-area-context';

export default function TransactionHistoryList({data}: {data: any}) {

  const [loadMore, setLoadMore] = useState('true')

  const _handleLoadMore = () => {
   //what to put here
  }

  const extractKey = ({
    id,
  }: {
    id: any;
    name: any;
    accountNumber: any;
    type: any;
    amount: any;
  }) => id;

  const renderSeparator = () => {

    return (
      <View
        style={{
          height: 1,
          width: '94%',
          backgroundColor: '#000',
          alignSelf: 'center',
        }}
      />
    );
  };

  const footerComponent = () => {
    if (!_handleLoadMore) return null;
    return (
      <View
        style={{
          position: 'relative',
          paddingVertical: 20,
          borderTopWidth: 1,
          marginTop: 10,
          marginBottom: 10,
        }}>
        <ActivityIndicator
          animating
          size="small"
          color="#CED0CE"
          hidesWhenStopped={true}
        />
      </View>
    );
  };

  return (
    <SafeAreaView>
      <View style={styles.container}>
        <Text style={styles.transactionhistory}>Transaction History</Text>
        <SectionList
          contentContainerStyle={{paddingBottom: 500}}
          maxToRenderPerBatch={7}
          onEndReachedThreshold={2}
          updateCellsBatchingPeriod={4000}
          ItemSeparatorComponent={renderSeparator}
          sections={data}
          renderSectionHeader={({section}) => {
            return <Text style={styles.date}>{section.title}</Text>;
          }}
          renderItem={({item}) => {
            return (
              <View style={styles.item}>
                <Text>
                  <View>
                    <Text style={styles.name}>{item.name}</Text>
                    <Text style={styles.accountNumber}>
                      {item.accountNumber}
                    </Text>
                  </View>
                </Text>
                <View style={styles.amountContainer}>
                  <Text
                    style={[
                      item.type == 'in' ? styles.moneyIn : styles.moneyOut,
                    ]}>
                    {item.amount}
                  </Text>
                </View>
              </View>
            );
          }}
          ListFooterComponent= {footerComponent}
          keyExtractor={extractKey}
        />
      </View>
    </SafeAreaView>
  );
}

const styles = StyleSheet.create({
  container: {
    marginLeft: 20,
    marginRight: 20,
    marginTop: 120,
    flex: -200,
    //paddingBottom: 10
  },
  transactionhistory: {
    fontWeight: 'bold',
    fontSize: 18,
    paddingBottom: 10,
    paddingLeft: 25,
  },
  item: {
    flexDirection: 'row',
    justifyContent: 'space-between',
    marginRight: 20,
    marginLeft: 25,
    paddingBottom: 10,
    paddingTop: 10,
  },
  date: {
    padding: 10,
    marginBottom: 15,
    backgroundColor: '#e0e0e0',
    fontFamily: 'OpenSans-Bold',
    fontSize: 15,
    paddingLeft: 25,
  },
  name: {
    fontSize: 14,
    fontFamily: 'OpenSans-SemiBold',
  },
  accountNumber: {
    fontSize: 12,
    fontFamily: 'OpenSans-Regular',
  },
  amountContainer: {
    paddingTop: 8,
  },
  moneyIn: {
    color: '#689f38',
    letterSpacing: 0.8,
    fontSize: 16,
    fontFamily: 'OpenSans-SemiBold',
  },
  moneyOut: {
    color: '#b71c1c',
    letterSpacing: 0.8,
    fontSize: 16,
    fontFamily: 'OpenSans-SemiBold',
  },
  loading: {
    color: '#CED0CE',
  },
});


  

Ответ №1:

раздел-список поддерживает событие прокрутки, и вы можете довольно плавно скрывать / показывать функцию индикатора активности с помощью функции прокрутки

Пример:

 const isCloseToBottom = ({layoutMeasurement, contentOffset, contentSize}) => {
  const paddingToBottom = 20;
  return layoutMeasurement.height   contentOffset.y >=
    contentSize.height - paddingToBottom;
};


    <SectionList
      contentContainerStyle={{paddingBottom: 500}}
      maxToRenderPerBatch={7}
      onEndReachedThreshold={2}
      onScroll={({nativeEvent}) => {
         if (isCloseToBottom(nativeEvent)) {
             if(!this.state.fetching_status){
               //what you want to do when the screen reached end of screen
               //console.log or something usefull
              }
         }
     }} 
    .../>
  

Комментарии:

1. Спасибо за ответ, но должен ли я создать ‘isCloseToBottom’ ? И может ‘(!this.state. fetching_status)’ допустимо в функциональном компоненте ?

2. @sarah.isml Я обновил код, добавив функцию isCloseToBottom

3. Могу ли я узнать, что такое nativeEvent?

4. nativeEvent — это объект, который предоставляется функцией onScroll

5. { nativeEvent: { contentInset: {нижний, левый, правый, верхний}, contentOffset: {x, y}, contentSize: {высота, ширина}, layoutMeasurement: {высота, ширина}, масштабирование } }

Ответ №2:

Я думаю, что в вашем случае можно использовать onEndReached prop из SectionListhttps://reactnative.dev/docs/sectionlist#onendreached Это правильное место для записи вашей логики для загрузки следующей «страницы» ваших элементов