前言
在开发过程中,遇到要请求几千行数据的需求,因为前端部分已经使用了VirtualList
虚拟列表只渲染当前可视区域的视图,非可视区域的视图在用户滚动到可视区域再渲染:
但仍不能解决数据加载缓慢问题。原因是数据量本身太大,导致传输的速度过慢,所以渲染到页面上的速度也很慢。
解决方案
用请求分片的方式,先加载前50条数据,监听滑动到底部的事件,当列表下拉到底部的时候,再去请求后一百条数据。这么做每次只请求50条数据,传输速度就会很快。
前端具体实现如下:
function PoemList() {
...
// 设置请求偏移量
const [offset, setOffset] = useState<number>(0);
useEffect(() => {
...
// 第一次请求
getPoemList(category, offset)
.then((res) => {
setList(res);
})
.catch((err) => {
console.error(err);
});
}
}, []);
// 监听滑动到底部的事件
const handleScrollToLower = () => {
console.log('scroll to lower!!');
const curOffset = offset + 1;
setOffset(curOffset);
// 后续请求,每次请求100条数据,这个100条是在后端根据offset控制的
getPoemList(category, curOffset)
.then((res) => {
setList(list.concat(res));
})
.catch((err) => {
console.error(err);
});
};
......
return (
<View className="poemList-container">
<View className="top">
<View className="title">{title}</View>
<View className="desc">{desc}</View>
</View>
{list.length > 0 && (
<VirtualList
height={800} /* 列表的高度 */
width="100%" /* 列表的宽度 */
itemData={list} /* 渲染列表的数据 */
itemCount={list.length} /* 渲染列表的长度 */
itemSize={80} /* 列表单项的高度 */
onScrollToLower={handleScrollToLower}>
{listItem}
</VirtualList>
)}
</View>
);
}
export default React.memo(PoemList);
后端具体实现:
const Service = require('egg').Service;
class PoemListService extends Service {
async getPoemList(category, offset) {
const res = await this.findPoemList(category, offset*50);
return res;
}
async findPoemList(category, offset) {
const { ctx } = this;
// 分片获取数据
switch (category) {
case 0: {
const res = await ctx.model.Poems.findAll({
offset: offset,
limit: 50,
});
return res;
}
case 1: {
const res = await ctx.model.Poetry.findAll({
offset: offset,
limit: 50,
});
return res;
}
case 2: {
const res = await ctx.model.Lunyu.findAll({
offset: offset,
limit: 50,
});
return res;
}
case 3: {
const res = await ctx.model.Shijing.findAll({
offset: offset,
limit: 50,
});
return res;
}
}
}
}
module.exports = PoemListService;
这里用到sequelize
ORM。offset用于设置开始请求的偏移量(比如,如果offset为50,表示跳过前面49条数据,从第50条数据开始获取),limit
表示数量。