问题点
- 如果一次加载 10 条数据,但是页面高度很高,不会显示滚动条,比如再大屏幕显示,会导致 hasMore=true
- loader 内容会一直显示,但是不加载数据,给人卡顿的体验。
解决
- 只要有滚动条,load 就显示正常
- 初始化多加载些数据,比如 100 条,然后每次滚动触发 next 再次加载
无限滚动方案二
Intersection Observer API
案例参考
https://dev.to/vishnusatheesh/exploring-infinite-scroll-techniques-in-react-1bn0
react-infinite-scroll-component
https://github.com/ankeetmaini/react-infinite-scroll-component
https://www.npmjs.com/package/react-infinite-scroll-component
https://www.jianshu.com/p/4bb28664ad74
// yarn add react-infinite-scroll-component
import React, { useRef } from 'react'
import { Skeleton, Divider } from 'antd'
import InfiniteScroll from 'react-infinite-scroll-component'
import clsx from 'clsx'
type IProps = {
children: React.ReactNode,
fetchMore: () => void;
dataLength: number;
hasMore: boolean;
loading: boolean;
};
function ScrollList(props: IProps){
const {
children,
fetchMore,
dataLength,
hasMore = false,
loading = false,
className
} = props;
const domRef = useRef<HTMLDivElement>(null);
return (
<section
ref={domRef}
className={clsx('overflow-x-hidden overflow-y-auto ',className)}
>
<InfiniteScroll
dataLength={dataLength}
next={fetchMore}
hasMore={hasMore}
scrollableTarget={domRef.current}
// 小于20条数据全部展示
endMessage={
dataLength > 20
? <Divider plain>已全部加载</Divider>
: false
}
loader={(
<Skeleton
avatar={{ shape: 'square' }}
paragraph={{ rows: 3 }}
active
className="mt16"
/>
)}
>
{children}
</InfiniteScroll>
</section>
);
}
export default ScrollList;
InfiniteScroll
import React, { useEffect, useMemo, useState } from 'react';
import { useRequest } from 'ahooks';
import { ScrollList, InputSearch, isSuccess, requestOptions } from '@/components';
const initPage = { page: 1, limit: 10 }
function App() {
const [dataSource, setDataSource] = useState([]);
const [page, setPage] = useState(initPage);
// 初始化数据标识
const [initFlag, setInitFlag] = useState(true);
// 获取列表
const { data = { total: 0 }, runAsync, loading } = useRequest(getUsers, requestOptions);
const hasMore = useMemo(() => dataSource.length < data.total, [dataSource, data.total]);
useEffect(() => {
init();
}, [page, initFlag]);
async function init() {
const res = await runAsync(page);
if (!isSuccess(res)) return;
// 初始化数据
if (flag) {
return setSource(res.data);
}
// 加载更多合并数据
setDataSource(prevState => prevState.concat(res.data));
}
// 向下滚动触发的事件,用于更新 page++
async function fetchMore() {
// 合并数据,不要初始化
setInitFlag(false);
setPage(prevState => {
return { ...prevState, page: prevState.page + 1 }
});
}
async function onSearch(name) {
const payload = name ? { ...initPage, name } : initPage;
// 搜索初始化数据
setInitFlag(true);
setPage(payload);
}
function renderItem(item) {
return (
<Col span={8} key={item.id}>
<Card>{item.name}</Card>
</Col>
)
}
return (
<PageContainer>
<InputSearch onSearch={onSearch} />
<Spin spinning={page.page === 1 ? loading : false}>
<ScrollList
fetchMore={fetchMore}
hasMore={hasMore}
dataLength={dataSource.length}
>
<Row gutter={[24, 24]} className="w-full">
{dataSource.map(renderItem)}
</Row>
</ScrollList>
</Spin>
</PageContainer>
)
}
export default App
推送列表滚动
https://www.jq22.com/yanshi22468
https://www.jq22.com/demo/jquerylistScroll201911081901/