我们已经实现了文章列表的分页查询,接下来我们需要实现文章列表的条件查询 .

1. 条件查询布局

如果之前学过不凡学院的乐居商城后台管理系统,那么这一块的布局思路应该非常熟悉:
image.png

  1. <PageContainer className={styles.main}>
  2. <Card className={styles.searchBar}>
  3. <Form
  4. labelCol={{
  5. span: 4,
  6. }}
  7. wrapperCol={{
  8. span: 20,
  9. }}
  10. layout="inline"
  11. >
  12. <Row gutter={[20,30]} style={{width:'100%'}}>
  13. <Col span={6}>
  14. <Form.Item label="标题" name="title">
  15. <Input />
  16. </Form.Item>
  17. </Col>
  18. <Col span={6}>
  19. <Form.Item label="作者" name="author">
  20. <Input />
  21. </Form.Item>
  22. </Col>
  23. <Col span={6} offset={18}>
  24. <Form.Item>
  25. <Button type="ghost">重置</Button>
  26. <Button type="primary" htmlType="submit" style={{marginLeft: '20px'}}>
  27. 查询
  28. </Button>
  29. </Form.Item>
  30. </Col>
  31. </Row>
  32. </Form>
  33. </Card>
  34. ...
  35. </PageContainer>
  36. // ==> ./index.less
  37. .main{
  38. .searchBar{
  39. background-color: #fff;
  40. margin-bottom: 30px;
  41. }
  42. }

image.png

2. 实现查询功能

  1. // React是导出的默认组件,所以不需要加{},而useEffect是单独导出的组件,需要加{}
  2. import React, { useEffect, useState } from 'react';
  3. import { PageContainer } from '@ant-design/pro-layout';
  4. // 引入connect
  5. import { connect } from 'umi';
  6. import type { Dispatch } from 'umi';
  7. import type { MStateType } from './model';
  8. import { Table, Card, Form, Input, Button, Row, Col } from 'antd';
  9. import { pickBy } from 'lodash';
  10. import type { ConnectState } from '@/models/connect.d';
  11. // 声明命名空间
  12. const namespace = 'article';
  13. // 声明props类型
  14. type PropsType = {
  15. articleList: []; // ??
  16. dispatch: Dispatch;
  17. totalCount: number;
  18. loading: boolean;
  19. };
  20. const ArticleList: React.FC<PropsType> = (props) => {
  21. // 解构需要用的内容
  22. const { articleList, totalCount, dispatch, loading } = props;
  23. // 某个数据是动态的 我们就得使用"响应式"对象得形式声明,也就是说哪写值变化了,需要更新页面,就需要声明成state
  24. // 在函数式组件中,因为无法使用this,所以提出来hook形式解决
  25. // useState 返回了一个数组,第一个参数是变量(响应式对象)名称,第二个是函数名,可以通过第二个函数更新这个变量
  26. const [pageStart, setPageStart] = useState<number>(1);
  27. const [pageSize, setPageSize] = useState<number>(10);
  28. // 定义查询条件
  29. const [params, setParams] = useState({});
  30. // 发送请求 尝试发送请求
  31. // 声明周期函数
  32. // componentDidMount(){
  33. // }
  34. // useEffect是多个生命周期函数的集合,考虑在这里进行数据初始化/请求
  35. // useEffect 第一个参数是函数类型,用于触发事件, 第二个参数是依赖于哪写数据的变化才触发
  36. // 如果只希望在第一次进入的时候触发一次,那么第二个参数为[]数组
  37. // useEffect componetDidMount componentDidUpdate componentWillUnmount
  38. useEffect(() => {
  39. dispatch({
  40. type: `${namespace}/findArticleList`,
  41. payload: {
  42. start: pageStart,
  43. limit: pageSize,
  44. params,
  45. },
  46. });
  47. }, [pageStart, pageSize, params]);
  48. // 用于控制数据列
  49. const columns = [
  50. {
  51. title: 'id',
  52. dataIndex: 'id',
  53. key: 'id',
  54. },
  55. {
  56. title: '标题',
  57. dataIndex: 'title',
  58. key: 'title',
  59. },
  60. {
  61. title: '作者',
  62. dataIndex: 'author',
  63. key: 'author',
  64. },
  65. {
  66. title: '概要描述',
  67. dataIndex: 'summary',
  68. key: 'summary',
  69. },
  70. {
  71. title: '创建时间',
  72. dataIndex: 'createTime',
  73. key: 'createTime',
  74. },
  75. ];
  76. // 比葫芦画瓢 找到form组件 定义了form的ref
  77. const [form] = Form.useForm();
  78. const onChange = (pageNumber: number, pSize?: number) => {
  79. // 页面变化的时候触发 需要更改分页变化
  80. // console.log('Page: ', pageNumber,pSize);
  81. setPageStart(pageNumber);
  82. setPageSize(pSize!);
  83. };
  84. // 查询的时候触发 如果需要刷新页面,本质需求是改变params对象 触发effect
  85. const onSearch = (value: { title?: string; author?: string }) => {
  86. // {author: 'zs', title: undefined} => {author: 'zs'}
  87. let useParams = { ...value };
  88. useParams = pickBy(useParams, (item) => item);
  89. // console.log(useParams);
  90. setParams({
  91. ...useParams,
  92. });
  93. };
  94. const resetSearch = () => {
  95. form.resetFields();
  96. setParams({});
  97. };
  98. return (
  99. <PageContainer>
  100. <Card title="条件查询" style={{ width: '100%', marginBottom: '30px' }}>
  101. <Form labelCol={{ span: 6 }} wrapperCol={{ span: 18 }} onFinish={onSearch} form={form}>
  102. <Row gutter={32}>
  103. <Col span={6}>
  104. <Form.Item label="标题" name="title">
  105. <Input />
  106. </Form.Item>
  107. </Col>
  108. <Col span={6}>
  109. <Form.Item label="作者" name="author">
  110. <Input />
  111. </Form.Item>
  112. </Col>
  113. </Row>
  114. <Row gutter={32}>
  115. <Col span={6} offset={18} style={{ textAlign: 'right' }}>
  116. <Button onClick={resetSearch}>重置</Button>
  117. {/* htmlType="submit" 把button变成表单默认提交按钮 用于触发onFinish */}
  118. <Button type="primary" style={{ marginLeft: 30 }} htmlType="submit">
  119. 查询
  120. </Button>
  121. </Col>
  122. </Row>
  123. </Form>
  124. </Card>
  125. <Table
  126. loading={loading}
  127. pagination={{
  128. showQuickJumper: true,
  129. showSizeChanger: true,
  130. current: pageStart,
  131. pageSize,
  132. total: totalCount,
  133. onChange,
  134. }}
  135. rowKey="id"
  136. dataSource={articleList}
  137. columns={columns}
  138. />
  139. ;
  140. </PageContainer>
  141. );
  142. };
  143. // 绑定model和组件 把state映射到props
  144. // 自定义的state不符合,但是可以合并connect.d.ts中的connectState
  145. type StateType = {
  146. [namespace]: MStateType;
  147. } & ConnectState;
  148. const mapStateToProps = (state: StateType) => ({
  149. articleList: state[namespace].articleList,
  150. totalCount: state[namespace].totalCount,
  151. loading: state.loading.effects['article/findArticleList'] as boolean,
  152. });
  153. export default connect(mapStateToProps)(ArticleList);

总结: 分页查询和条件查询我们已经基本实现, 跟vue相比, useEffect 确实很方便 . 接下来我们实现文章的新增功能.