//@ts-ignore import React, { useEffect, useRef, useState, useMemo } from 'react'; //@ts-ignore import { FlatList, FlatListProps, RefreshControl, View, TextStyle, StyleProp, ViewStyle } from 'react-native'; import NoData from './StyledNoData'; import StyledIndicator from './StyledIndicator'; interface Props extends FlatListProps<any> { [key: string]: any; FlatListComponent?: React.FunctionComponent<any>; loading?: boolean; data: any[]; loadingMore?: boolean; noDataText?: string; ListHeaderComponent?: any; scrollEnabled?: boolean; noDataCanRefresh?: boolean; i18Params?: any; noDataTextI18Key?: any; noDataStyle?: StyleProp<ViewStyle>; customStyle?: any; onLoadMore?(): void; onNoDataRefresh?(): void; } const StyledList = (props: Props, ref: any) => { const [momentumScrolled, setMomentumScrolled] = useState(false); const list = useRef<FlatList>(null); const { loading, loadingMore, data, ListHeaderComponent, refreshing, customStyle } = props; const contentContainerStyle: StyleProp<ViewStyle> = {}; const hasData = data?.length !== 0; if (!hasData) { contentContainerStyle.flex = 1; // contentContainerStyle.alignItems = 'center' // contentContainerStyle.justifyContent = 'center' } let styles: StyleProp<ViewStyle>; if (typeof ListHeaderComponent === 'undefined' && !hasData) { styles = [contentContainerStyle, customStyle]; } else { styles = customStyle; } function keyExtractor(item: any, i: any): string { return `${i}`; } function handleRefresh() { if (props.onRefresh) props.onRefresh(); } // Bởi vì onEnReached call nhiều lần nên phải trick để chỉ call 1 lần thôi useEffect(() => { if (momentumScrolled) { setMomentumScrolled(true); if (props.onLoadMore) props.onLoadMore(); } }, [momentumScrolled]); function handleEndReached(info: any) { if (!momentumScrolled) { setMomentumScrolled(true); } } function handleNoDataRefresh() { const { onNoDataRefresh } = props; if (onNoDataRefresh) onNoDataRefresh(); } function onMomentumScrollBegin() { setMomentumScrolled(false); } React.useImperativeHandle(ref, () => ({ scrollToTop: () => { list?.current?.scrollToOffset({ animated: true, offset: 0 }); }, })); function renderFooter() { if (hasData && loadingMore) { return ( <View style={{ alignItems: 'center', marginVertical: 8 }}> <StyledIndicator size={24} /> </View> ); } return null; } function renderNoData() { const { noDataText, noDataTextI18Key, noDataCanRefresh } = props; return ( <NoData customStyle={props.noDataStyle} loading={loading} text={"No data"} canRefresh={noDataCanRefresh} onRefresh={handleNoDataRefresh} /> ); } const FlatListComponent: any = useMemo(() => { return props?.FlatListComponent || FlatList; }, [props?.FlatListComponent]); return ( <FlatListComponent ref={list} contentContainerStyle={styles} keyExtractor={keyExtractor} initialNumToRender={10} // onEndReached={handleEndReached} onEndReachedThreshold={0.01} onMomentumScrollBegin={onMomentumScrollBegin} ListEmptyComponent={renderNoData} showsVerticalScrollIndicator={false} refreshControl={ <RefreshControl refreshing={!!refreshing} colors={['red']} tintColor={"blue"} onRefresh={handleRefresh} /> } ListFooterComponent={renderFooter} keyboardShouldPersistTaps={'never'} {...props} /> ); }; export default React.memo(React.forwardRef(StyledList));