React&Nest.js全栈社区平台(五)——👋封装通用分页Service实现文章流与详情

简介: React&Nest.js全栈社区平台(五)——👋封装通用分页Service实现文章流与详情

前言

前面我们已经实现了文章发布与文章管理功能,今天我们来实现首页的文章流列表以及查看文章详情的功能。

往期文章

仓库地址

  • 切图仔做全栈:React&Nest.js 社区平台(一)——基础架构与邮箱注册、JWT 登录实现
  • 切图仔做全栈:React&Nest.js社区平台(二)——👋手把手实现优雅的鉴权机制
  • React&Nest.js全栈社区平台(三)——🐘对象存储是什么?为什么要用它?
  • React&Nest.js社区平台(四)——✏️文章发布与管理实战

后端实现

对于文章列表来说,无论前端以什么样的形式去展现,表格也好,滚动刷新的列表也好,它本质上是一个分页的需求。

对于分页的需求相信每个前端都不陌生,你平时对接的时候把页码跟每一页的条数提供给后端后,后端会根据这些信息取出对应的条数返回给前端。

比如下面的 sql 语句,它指的是在 users 表中,从 第10条 开始,取 10条 数据,大多数的分页场景都是基于这个 sql 语句。

SELECT * FROM users offset 10 limit 10;

这一期我们会封装一个通用的分页 service ,接受任意一个 entity 对象,去查询分页信息。

通用分页Service封装

首先先定义一下分页 service 的返回值:

export class PaginationResult<T> {
  total: number;
  pageSize: number;
  currentPage: number;
  totalPage: number;
  isEnd: boolean;
  list: T[];
}

它接收一个范型参数 T ,对应的是传入的 entity 对象,其他的参数解释如下:

  • total :总条数
  • pageSize :每页条数
  • currentPage :当前页
  • totalPage :总共有多少页
  • isEnd :是否还有下一页
  • list :查询出来的列表对象

整个分页 service 实现如下:

export class PaginationService<T> {
  constructor(private repository: Repository<T>) {}

  async paginate(params: {
    page: number;
    pageSize: number;
    options?: FindOneOptions<T>;
  }): Promise<PaginationResult<T>> {
    const { page, pageSize, options = {} } = params;
    const [result, total] = await this.repository.findAndCount({
      take: pageSize,
      skip: pageSize * (page - 1),
      ...options,
    });

    const paginationResult = new PaginationResult<T>();
    paginationResult.list = result;
    paginationResult.total = total;
    paginationResult.pageSize = pageSize;
    paginationResult.currentPage = page;
    paginationResult.totalPage = Math.ceil(total / pageSize);
    paginationResult.isEnd = paginationResult.totalPage === page;

    return paginationResult;
  }
}

解释一下上面的代码:

  • 整个类接收一个范型对象 T ,它对应的是需要查询的 entity 对象
  • 构造函数中接收一个 repository ,它是范型 T(entity对象) 所对应的 repository
  • 首先接收页码参数 page ,每一页的条数 pageSize ,以及一个拓展查询条件 optionsoptions 的类型是 TypeORM 中的 FindOneOptions
  • 使用 findAndCount 查询出当前条件的条数以及结果,其中 take 对应原生 sql 语句的 limitskip 对应原生 sql 语句的 offset
  • 最后组装一下参数返回给调用方

文章列表接口

有了上面这个通用的分页器之后,我们可以在 artice.service 中实现一下获取分页文章列表的方法。

  async getArticles(params: { page: number; pageSize: number }) {
    const paginationService = new PaginationService<ArticleEntity>(
      this.articleRepository,
    );
    const res = await paginationService.paginate({
      ...params,
      options: {
        select: ['id', 'categoryId', 'introduction', 'title', 'creatorName'],
        where: { status: 1, isDeleted: 0 },
      },
    });
    return res;
  }

使用 ArticleEntity 跟注入的 articleRepositorynew 一个分页 service ,然后调用它的 paginate 方法。

这里把前端传过来的页码和每页的条数传进去,别忘了只能把已发布的文章 (status=1) 和未删除的文章查出来 (is_deleted=0)

值得一提的是,因为我们使用了范型以及对 options 定义了 FindOneOptions 这个类型,所以在开发的过程中, ts 的类型推断可以帮我们自动提示一些东西。

比如说我要选择某一些字段,在 select 数组中书写时,会对应提示 ArticleEntity 里有的字段,十分的方便。

image.png

整个接口的返回值如下图所示:

image.png

前端实现

前端方面使用 react-infinite-scroll-component 这个无限滚动组件配合 antd 的列表组件来实现一个滚动加载的分页列表。

      <div id="scrollableDiv" className={styles.list}>
        <InfiniteScroll
          dataLength={article.total}
          next={() => setPageNo(pageNo + 1)}
          hasMore={!article.isEnd}
          loader={<Skeleton avatar paragraph={{ rows: 1 }} active />}
          endMessage={<Divider plain>到底了~</Divider>}
          scrollableTarget="scrollableDiv"
        >
          <List
            dataSource={article.list}
            renderItem={(item: any) => (
              <List.Item
                className={styles.listItem}
                onClick={() => navigate(`/detail?id=${item.id}`)}
                key={item.id}
              >
                <List.Item.Meta
                  title={item.title}
                  description={
                    <>
                      <div style={{ margin: "8px 0" }}>{item.introduction}</div>
                      <Tag>{categoryMap[item.categoryId]}</Tag>
                    </>
                  }
                />
              </List.Item>
            )}
          />
        </InfiniteScroll>
      </div>

当页面滚动到底部时,会去拉取下一页的列表,同时根据我们上面 service 中返回的 isEnd 字段判断列表是否已经完全加载完毕。

image.png

image.png

有了文章列表之后必不可少的当然是文章详情,文章详情的接口就是根据文章 id 去查询一条记录,代码比较简单,这里就不放出来了。

前端要做的事情就是解析数据库里面存储的 markdown 内容为 html ,然后渲染到页面上,这里我使用的是 react-markdown 这个库,当然你可以搭配别的选择,或者自研一个。

至于样式什么的,就看你自己自由发挥了。

<div className={styles.content}>
    <ReactMarkdown children={article.content} />
</div>

image.png

最后

以上就是本文的全部内容,我们一起封装了一个通用的分页类,它可以方便的在各个 Entity 中实现分页的需求,然后我们还实现了文章流和文章详情,到这里,我们的社区平台基本上也算是做到了管理文章+查看文章的功能。

如果你觉得有意思的话,点点关注点点赞吧~欢迎在评论区交流

相关文章
|
26天前
|
JavaScript 前端开发 算法
虚拟DOM是React的关键技术,它是个轻量的JS对象树,模拟实际DOM结构。
【6月更文挑战第27天】虚拟DOM是React的关键技术,它是个轻量的JS对象树,模拟实际DOM结构。当状态改变,React不直接修改DOM,而是先构建新的虚拟DOM树。通过 diff 算法比较新旧树,找到最小变更,仅更新必要部分,提高性能,避免频繁DOM操作。虚拟DOM还支持跨平台应用,如React Native。它优化了更新流程,简化开发,并提升了用户体验。
21 1
|
26天前
|
前端开发 JavaScript 开发者
探索现代前端框架:从React到Vue.js
【6月更文挑战第26天】在数字时代的浪潮中,前端框架如同建筑的基石,支撑着互联网界面的创新与发展。本文将带领读者穿梭于React与Vue.js这两个最受欢迎的前端框架之间,揭示它们的核心特性、设计理念以及在实际开发中的应用差异。通过比较分析,我们将理解每个框架的优势和局限,并探索如何根据项目需求作出明智的选择。加入我们,一起深入前端技术的瑰丽世界,发现构建未来网络界面的无限可能。
|
17天前
|
前端开发
Vue3 【仿 react 的 hook】封装 useTitle
Vue3 【仿 react 的 hook】封装 useTitle
9 0
|
17天前
|
前端开发 API
Vue3 【仿 react 的 hook】封装 useLocation
Vue3 【仿 react 的 hook】封装 useLocation
10 0
|
19天前
|
JavaScript 前端开发
vitepress初始化安装,最全 “vitepress > @docsearch/js > @docsearch/react > ,ENOENT: no such file or
vitepress初始化安装,最全 “vitepress > @docsearch/js > @docsearch/react > ,ENOENT: no such file or
|
1月前
|
前端开发 API
|
2月前
|
前端开发 NoSQL JavaScript
基于 React + Nest 全栈开发的后台系统
这篇文章介绍了一个基于React+Nest全栈开发的后台系统XmwAdmin。项目包括前端和后端技术栈,线上预览地址和登录信息。作者推荐使用pnpm包管理工具和特定的环境依赖。文章提供了项目的运行和编译代码,以及各个功能模块的介绍。还包括演示图和项目活动以及总结部分。数据库下载链接也提供了,该项目已完成后台的核心功能。
基于 React + Nest 全栈开发的后台系统
|
2月前
|
JavaScript 前端开发 NoSQL
构建基于Node.js的全栈应用:从前端到后端的完整指南
【5月更文挑战第24天】本文是关于使用Node.js构建全栈应用的指南,涵盖前端(React或Vue)、后端(Node.js + Express)和数据库(MongoDB)的选型与实现。文章介绍了项目结构、前端组件化开发、后端API接口编写、前后端联调及部署上线的注意事项,帮助读者掌握全栈开发流程。
|
2月前
|
前端开发 网络架构 UED
React Next.js框架
React Next.js 是一个基于 React 的服务器渲染框架,用于构建高性能的现代Web应用。它提供内置的服务器渲染、静态导出、动态路由功能,并自动进行代码拆分。Next.js 还支持热模块替换、CSS-in-JS 和客户端路由,拥有丰富的插件生态系统,简化了开发过程,提升了应用的性能和用户体验。
|
2月前
|
缓存 前端开发 JavaScript
React和Next.js开发常见的HTTP请求方法
React和Next.js开发常见的HTTP请求方法
35 0