Last active
September 17, 2025 08:53
-
-
Save Blithe-Chiang/9fc2b184dd11456a9337354267d4339f to your computer and use it in GitHub Desktop.
CFlatList
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import {useLatest, useMemoizedFn, useMount, useUnmountedRef} from 'ahooks'; | |
| import React, {forwardRef, useImperativeHandle, useRef, useState} from 'react'; | |
| import {FlatList, FlatListProps} from 'react-native'; | |
| interface CFlatListProps<ItemT> { | |
| onFetch: ( | |
| isRefresh: boolean, | |
| success: (data: ItemT[], pageSize: number) => void, | |
| fail: (err: string) => void, | |
| ) => void; | |
| fetchOnMounted?: boolean; | |
| } | |
| export interface CFlatListRef<ItemT> { | |
| updateListData: (updater: (prevData: ItemT[]) => ItemT[]) => void; | |
| getListData: () => ItemT[]; | |
| scrollToTop: () => void; | |
| } | |
| function CFlatList<ItemT>( | |
| props: CFlatListProps<ItemT> & | |
| Omit<FlatListProps<ItemT>, 'data' | 'onRefresh'>, | |
| ref: React.Ref<CFlatListRef<ItemT>>, | |
| ) { | |
| const {onFetch, fetchOnMounted = true, onEndReached, ...restProps} = props; | |
| const [listData, setListData] = useState<ItemT[]>([]); | |
| const [refreshing, setRefreshing] = useState(false); | |
| const [hasMore, setHasMore] = useState(false); | |
| const unmountedRef = useUnmountedRef(); | |
| const listDataRef = useLatest(listData); | |
| useMount(() => { | |
| if (fetchOnMounted) { | |
| _onFetch(true); | |
| } | |
| }); | |
| const success = useMemoizedFn( | |
| (_data: ItemT[], pageSize: number, isRefresh: boolean) => { | |
| if (unmountedRef.current) return; | |
| if (isRefresh) { | |
| setListData(_data); | |
| } else { | |
| setListData(prevData => [...prevData, ..._data]); | |
| } | |
| const hasMore = _data.length >= pageSize; | |
| setHasMore(hasMore); | |
| setRefreshing(false); | |
| }, | |
| ); | |
| const fail = useMemoizedFn(() => { | |
| if (unmountedRef.current) return; | |
| setRefreshing(false); | |
| }); | |
| const _onFetch = useMemoizedFn((isRefresh = false) => { | |
| if (!isRefresh && !hasMore) return; | |
| onFetch( | |
| isRefresh, | |
| (data, pageSize) => success(data, pageSize, isRefresh), | |
| fail, | |
| ); | |
| }); | |
| useImperativeHandle( | |
| ref, | |
| () => ({ | |
| updateListData: (updater: (prevData: ItemT[]) => ItemT[]) => { | |
| setListData(prevData => updater(prevData)); | |
| }, | |
| getListData: () => listDataRef.current, | |
| scrollToTop: () => { | |
| flatListRef.current?.scrollToIndex({ | |
| animated: true, | |
| index: 0, | |
| }); | |
| }, | |
| }), | |
| [listDataRef], | |
| ); | |
| const flatListRef = useRef<FlatList<ItemT>>(null); | |
| return ( | |
| <FlatList | |
| ref={flatListRef} | |
| data={listData} | |
| refreshing={refreshing} | |
| onRefresh={() => _onFetch(true)} | |
| onEndReached={info => { | |
| onEndReached?.(info); | |
| _onFetch(false); | |
| }} | |
| {...restProps} | |
| /> | |
| ); | |
| } | |
| export default forwardRef(CFlatList) as <ItemT>( | |
| props: CFlatListProps<ItemT> & | |
| Omit<FlatListProps<ItemT>, 'data' | 'onRefresh'> & { | |
| ref?: React.Ref<CFlatListRef<ItemT>>; | |
| }, | |
| ) => React.ReactElement; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import { Text, View } from "react-native"; | |
| import CFlatList from "./CFlatList"; | |
| export default function Index() { | |
| const onFetch = (isRefresh: boolean, success: (data: any[], pageSize: number) => void, fail: (err: string) => void): void => { | |
| if (isRefresh) { | |
| success(getData(20), 20); | |
| return | |
| } | |
| success(getData(10), 10) | |
| }; | |
| return ( | |
| <View | |
| style={{ | |
| flex: 1, | |
| justifyContent: "center", | |
| alignItems: "center", | |
| }} | |
| > | |
| <CFlatList<{ id: number, title: string }> | |
| keyExtractor={(item) => item.id + ""} | |
| renderItem={({ item }) => <Text style={{ | |
| height: 50, | |
| }}>{item.title}</Text>} | |
| onFetch={onFetch} /> | |
| </View> | |
| ); | |
| } | |
| function getData(size: number = 10) { | |
| // generate random values | |
| return Array.from({ length: size }, (_, i) => { | |
| const id = Math.random(); | |
| return { | |
| title: `title ${id + 1}`, | |
| id: id + 1, | |
| }; | |
| }); | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment