当前位置: 首页 > news >正文

0803分页_加载更多-网络ajax请求2-react-仿低代码平台项目

文章目录

    • 1 分页
      • 1.1 url与分页参数
      • 1.2 分页组件与url
      • 1.3 列表页引用分页组件
    • 2 加载更多
      • 2.1 状态
      • 2.2 触发时机
      • 2.3 加载数据
      • 2.4优化
    • 结语

1 分页

1.1 url与分页参数

查询问卷列表接口,添加分页参数:

  • page:当前页码(第几页)
  • pageSize:每页多少条记录

question.ts 查询文件接口列表参数扩展,如下所示:

type SearchOption = {keyword: string;isStar: boolean;isDeleted: boolean;page: number;pageSize: number;
};

浏览器url获取分页参数,useLoadQuestionListData.ts代码如下所示:

import { useSearchParams } from "react-router-dom";
import { useRequest } from "ahooks";
import { getQuestionListApi } from "@/api/question";import {LIST_SEARCH_PARAM_KEY,LIST_PAGE_PARAM_KEY,LIST_PAGE_SIZE_PARAM_KEY,LIST_PAGE_SIZE_DEFAULT,LIST_PAGE_DEFAULT,
} from "@/constant";type OptionType = {isStar: boolean;isDeleted: boolean;page: number;pageSize: number;
};/*** 获取问卷列表* @returns 问卷列表*/
function useLoadQuestionListData(opt: Partial<OptionType>) {const { isStar, isDeleted } = opt;const [searchParams] = useSearchParams();const keyword = searchParams.get(LIST_SEARCH_PARAM_KEY) || "";const page =parseInt(searchParams.get(LIST_PAGE_PARAM_KEY) || "") || LIST_PAGE_DEFAULT ;const pageSize =parseInt(searchParams.get(LIST_PAGE_SIZE_PARAM_KEY) || "") ||LIST_PAGE_SIZE_DEFAULT;async function load() {const data = await getQuestionListApi({keyword,isStar,isDeleted,page,pageSize,});//...
}export default useLoadQuestionListData;

服务端解析分页参数,question.js代码如下:

const Mock = require('mockjs')const getQuestionList = require("./data/getQuestionList")const Random = Mock.Randommodule.exports = [// ...{// 获取问卷列表url: '/api/question',method: 'get',response(ctx) {const { query = {} } = ctxconst isStar = query.isStar === 'true'const isDeleted = query.isDeleted === 'true'const page = parseInt(query.page) || 1const pageSize = parseInt(query.pageSize) || 10return {errno: 0,data: {list: getQuestionList({isStar, isDeleted, page, pageSize}),total: 100}}}},
]

1.2 分页组件与url

antd分页组件与url交互

由于多个列表页面都需要分页组件,这里我们以antd分页组件为基础,封装自定义分页组件,并且实现分页参数与url参数交互,ListPage.tsx代码如下所示:

import { FC, useEffect, useState } from "react";
import { useLocation, useNavigate, useSearchParams } from "react-router-dom";
import { Pagination } from "antd";import {LIST_PAGE_DEFAULT,LIST_PAGE_PARAM_KEY,LIST_PAGE_SIZE_DEFAULT,LIST_PAGE_SIZE_PARAM_KEY,
} from "@/constant";type PropsType = {total: number;
};const ListPage: FC<PropsType> = (props: PropsType) => {const [current, setCurrent] = useState(LIST_PAGE_DEFAULT);const [pageSize, setPageSize] = useState(LIST_PAGE_SIZE_DEFAULT);const [searchParams] = useSearchParams();useEffect(() => {const curPage =parseInt(searchParams.get(LIST_PAGE_PARAM_KEY) || "") ||LIST_PAGE_DEFAULT;const curPageSize =parseInt(searchParams.get(LIST_PAGE_SIZE_PARAM_KEY) || "") ||LIST_PAGE_SIZE_DEFAULT;setCurrent(curPage);setPageSize(curPageSize);}, [searchParams]);const { total } = props;// 当page pageSize改变时,跳转页面(改变url)const nav = useNavigate();const { pathname } = useLocation();function handlePageChange(page: number, pageSize: number) {searchParams.set(LIST_PAGE_PARAM_KEY, page.toString());searchParams.set(LIST_PAGE_SIZE_PARAM_KEY, pageSize.toString());nav({pathname,search: searchParams.toString(),});}return (<Paginationcurrent={current}pageSize={pageSize}total={total}onChange={handlePageChange}/>);
};export default ListPage;

1.3 列表页引用分页组件

“星标问卷”列表页Star.tsx代码如下:

// ...
import ListPage from "@/components/ListPage";const List: FC = () => {// ...//问卷列表数据const { data = {}, loading } = useLoadQuestionListData({ isStar: true });const { list = [], total = 0 } = data;
// ...<div className={styles.footer}><ListPage total={total} /></div></>);
};export default List;

“回收站”列表页Trash.tsx代码如下所示:

import { FC, useState } from "react";
import { useTitle } from "ahooks";
import ListPage from "../../components/ListPage";const List: FC = () => {useTitle("调查问卷-回收站");//问卷列表数据const { data = {}, loading } = useLoadQuestionListData({ isDeleted: true });const { list = [], total = 0 } = data;
// ...<div className={styles.footer}><ListPage total={total} /></div></>);
};export default List;

在这里插入图片描述

2 加载更多

2.1 状态

基础

  • page:当前页
  • list:全部数据列表,上划累加
  • total:总条数

计算项

  • hasMoreData:是否有更多数据

2.2 触发时机

  • 页面加载触发
  • 页面滚动到加载更多数据时触发
    • 监听页面滚动
    • 防抖处理
    • DOM计算页面滚动刀”加载更多“

2.3 加载数据

  • useRequest请求接口
  • 接口返回数据,设置状态

2.4优化

  • 加载更多,缓存处理
  • 刷新页面优化暂无数据
  • 搜索重置状态

完整”我的问卷“页List.tsx代码如下所示:

import { FC, useEffect, useMemo, useRef, useState } from "react";
import { useSearchParams } from "react-router-dom";
import { useDebounceFn, useRequest, useTitle } from "ahooks";
import { Typography, Spin, Empty } from "antd";import QuestionCard from "@/components/QuestionCard";
import ListSearch from "@/components/ListSearch";
import styles from "./common.module.scss";
import { getQuestionListApi } from "@/api/question";
import { LIST_PAGE_SIZE_DEFAULT, LIST_SEARCH_PARAM_KEY } from "@/constant";const { Title } = Typography;const List: FC = () => {useTitle("调查问卷-我的问卷");//问卷列表数据const [started, setStarted] = useState(false);const [page, setPage] = useState(1);const [list, setList] = useState([]); // 全部列表数据,上划加载更多,累计const [total, setTotal] = useState(0);const hasMoreData = total > list.length;const [searchParams] = useSearchParams();const keyword = searchParams.get(LIST_SEARCH_PARAM_KEY) || "";// 搜索重置状态useEffect(() => {setStarted(false);setPage(1);setList([]);setTotal(0);}, [keyword]);// 加载数据const { run: loadData, loading } = useRequest(async () => {const data = await getQuestionListApi({page,pageSize: LIST_PAGE_SIZE_DEFAULT,keyword,});return data;},{manual: true,onSuccess(res) {const { list: newList = [], total = 0 } = res;// 累计数据setList(list.concat(newList));setTotal(total);setPage(page + 1);},});// 尝试触发加载-防抖处理const containerRef = useRef<HTMLDivElement>(null);const { run: tryLoadMore } = useDebounceFn(() => {const elem = containerRef.current;if (elem == null) {return;}// 判断如果div bottom 小于等于页面的高度const domRect = elem.getBoundingClientRect();if (domRect == null) {return;}const { bottom } = domRect;if (bottom <= document.body.clientHeight) {// 加载数据loadData();setStarted(true);}},{ wait: 500 });// 触发时机:页面加载或者url参数(keyword)变化时useEffect(() => {// 第一次加载,初始化tryLoadMore();}, [searchParams]);// 监听页面滚动事件useEffect(() => {if (hasMoreData) {window.addEventListener("scroll", tryLoadMore);}return () => {// 解绑事件window.removeEventListener("scroll", tryLoadMore);};}, [searchParams, hasMoreData]);// 加载更多显示优化const LoadMoreContentElem = useMemo(() => {if (!started || loading) {return <Spin />;}if (total === 0) {return <Empty description="暂无数据" />;}if (!hasMoreData) {return <span>没有更多了……</span>;}return <span>开始加载下一页</span>;}, [started, loading, hasMoreData]);return (<><div className={styles.header}><div className={styles.left}><Title level={3}>我的问卷</Title></div><div className={styles.right}><ListSearch /></div></div><div className={styles.content}>{list.length > 0 &&list.map((q: any) => {const { _id } = q;return <QuestionCard key={_id} {...q} />;})}</div><div className={styles.footer}><div ref={containerRef}>{LoadMoreContentElem}</div></div></>);
};export default List;

在这里插入图片描述

结语

❓QQ:806797785

⭐️仓库地址:https://gitee.com/gaogzhen

⭐️仓库地址:https://github.com/gaogzhen

[1]ahook官网[CP/OL].

[2]mock文档[CP/OL].

[3]Ant Design官网[CP/OL].

相关文章:

  • 【多线程】五、线程同步 条件变量
  • 逆向|dy|a_bogus|1.0.1.19-fix.01
  • RK3568 Debian调试记录
  • 基于强化学习的智能交通控制系统设计
  • 基于STM32单片机PWM讲解(HAL库)
  • html css js网页制作成品——HTML+CSS+js美甲店网页设计(5页)附源码
  • pytest 技术总结
  • Windows怎样使用curl下载文件
  • 大模型时代的语言格局演变:为什么是 JavaScript?
  • uml类关系(实现、继承,聚合、组合,依赖、关联)
  • Python并发编程全景解析:多线程、多进程与协程的深度对比
  • 职场十二法则-马方
  • 刚体运动 (位置向量 - 旋转矩阵) 笔记 1.1~1.3 (台大机器人学-林沛群)
  • Python Cookbook-6.11 缓存环的实现
  • 光子计算芯片进展评估:下一代AI算力突破的可能性
  • 逻辑运算符
  • C++之map
  • 缓存替换算法之 FIFO(先进先出)
  • L1-4 零头就抹了吧
  • 图解 Redis 事务 ACID特性 |源码解析|EXEC、WATCH、QUEUE
  • 我国首个大型通用光谱望远镜JUST在青海启动建设
  • 著名统计学家、北京工业大学应用数理学院首任院长王松桂逝世
  • 快捷公寓单间不足5平方米?公寓方:预订平台图片只是参考,已退房款
  • 敲定!今年将制定金融法、金融稳定法
  • 最高法知产庭年度报告:民事案件二审发回重审率持续下降
  • 比亚迪一季度日赚亿元,净利润同比翻倍至91.55亿元