@uiw/react-native
Version:
UIW for React Native
149 lines (145 loc) • 4.22 kB
JavaScript
import React, { useState, useEffect, forwardRef, useImperativeHandle } from 'react';
import { FlatList } from 'react-native';
import { emptyDataView, activityIndicatorView, noMoreDataView } from './View';
const QuickList = (props, ref) => {
const {
onFetch,
// 请求的接口 Promise 类型
data,
// 数据源 Array 类型
renderItem = null,
// 渲染方法 Function 类型
keyId,
// 列表唯一 key
emptyView = emptyDataView,
pageSize = 10,
// 每次加载数据条数
total = 0,
// 总条数
style,
...others
} = props;
const PaginationStatus = {
firstLoad: 0,
// 首次加载
waiting: 1,
// 等待中
allLoaded: 2 // 全部加载完成
};
// 挂载状态
let mounted = true;
const [endReachedTime, setEndReachedTime] = useState(Date.now());
// 首次加载标识
const [firstLoader, setFirstLoader] = useState(true);
// 上拉加载 loading
const [loading, setLoading] = useState(false);
// 下拉刷新 refreshing
const [refreshing, setRefreshing] = useState(false);
// 页数 page number
const [page, setPage] = useState(1);
// 初始页面状态
const [paginationStatus, setPaginationStatus] = useState(PaginationStatus.firstLoad);
// 暴露给父组件调用的方法
useImperativeHandle(ref, () => ({
executeRefreshAction: async (param = {}) => {
setPage(1);
const params = {
page: 1,
pageSize,
...param
};
onFetch && (await onFetch(params));
}
}));
useEffect(() => {
// 挂载列表
mounted = true;
// 挂载完成首次执行加载
firstLoader && firstLoad().catch(error => {
console.error(error);
});
return () => {
// 卸载列表
mounted = false;
};
}, [firstLoader]);
useEffect(() => {
// 首次加载和总量为0时候直接返回
if (firstLoader || total === 0) {
return;
}
let maxPage = Math.ceil(total / pageSize);
if (maxPage === page) {
setPaginationStatus(PaginationStatus.allLoaded);
} else {
setPaginationStatus(PaginationStatus.waiting);
}
}, [page, total, firstLoader, pageSize]);
const renderFooter = () => {
if (total === 0) {
return null;
} else if (paginationStatus === PaginationStatus.waiting) {
return activityIndicatorView;
} else if (!loading && paginationStatus === PaginationStatus.allLoaded && total !== 0) {
return noMoreDataView;
}
};
const renderEmptyView = () => {
if (!firstLoader && typeof emptyView === 'function') {
return emptyView();
}
return null;
};
// 首次加载
const firstLoad = async () => {
if (paginationStatus === PaginationStatus.firstLoad) {
setPage(1);
setRefreshing(true);
const params = {
page: 1,
pageSize,
isRefresh: true
};
await onFetch(params);
setRefreshing(false);
setFirstLoader(false);
}
};
// 下拉刷新列表
const onRefresh = async () => {
if (mounted && !loading) {
setPage(1);
setRefreshing(true);
const params = {
page: 1,
pageSize,
isRefresh: true
};
await onFetch(params);
setRefreshing(false);
}
};
// 上拉加载更多
const onEndReached = async () => {
if (paginationStatus === PaginationStatus.firstLoad || paginationStatus === PaginationStatus.allLoaded || refreshing || loading) {
return;
}
setLoading(true);
const params = {
page: page + 1,
pageSize,
isRefresh: false
};
await onFetch(params);
setLoading(false);
setPage(page + 1);
};
return <FlatList {...others} ref={ref} onEndReachedThreshold={0.1} data={data} renderItem={renderItem} refreshing={refreshing} extraData={data} keyExtractor={item => item[keyId]} initialNumToRender={pageSize} onRefresh={onRefresh} onEndReached={() => {
const now = Date.now();
if (now - endReachedTime > 1000) {
onEndReached && onEndReached();
setEndReachedTime(now);
}
}} ListFooterComponent={renderFooter()} ListEmptyComponent={renderEmptyView()} style={style} />;
};
export default forwardRef(QuickList);