我们已经实现了文章列表的分页查询,接下来我们需要实现文章列表的条件查询 .
1. 条件查询布局
如果之前学过不凡学院的乐居商城后台管理系统,那么这一块的布局思路应该非常熟悉:
<PageContainer className={styles.main}>
<Card className={styles.searchBar}>
<Form
labelCol={{
span: 4,
}}
wrapperCol={{
span: 20,
}}
layout="inline"
>
<Row gutter={[20,30]} style={{width:'100%'}}>
<Col span={6}>
<Form.Item label="标题" name="title">
<Input />
</Form.Item>
</Col>
<Col span={6}>
<Form.Item label="作者" name="author">
<Input />
</Form.Item>
</Col>
<Col span={6} offset={18}>
<Form.Item>
<Button type="ghost">重置</Button>
<Button type="primary" htmlType="submit" style={{marginLeft: '20px'}}>
查询
</Button>
</Form.Item>
</Col>
</Row>
</Form>
</Card>
...
</PageContainer>
// ==> ./index.less
.main{
.searchBar{
background-color: #fff;
margin-bottom: 30px;
}
}
2. 实现查询功能
// React是导出的默认组件,所以不需要加{},而useEffect是单独导出的组件,需要加{}
import React, { useEffect, useState } from 'react';
import { PageContainer } from '@ant-design/pro-layout';
// 引入connect
import { connect } from 'umi';
import type { Dispatch } from 'umi';
import type { MStateType } from './model';
import { Table, Card, Form, Input, Button, Row, Col } from 'antd';
import { pickBy } from 'lodash';
import type { ConnectState } from '@/models/connect.d';
// 声明命名空间
const namespace = 'article';
// 声明props类型
type PropsType = {
articleList: []; // ??
dispatch: Dispatch;
totalCount: number;
loading: boolean;
};
const ArticleList: React.FC<PropsType> = (props) => {
// 解构需要用的内容
const { articleList, totalCount, dispatch, loading } = props;
// 某个数据是动态的 我们就得使用"响应式"对象得形式声明,也就是说哪写值变化了,需要更新页面,就需要声明成state
// 在函数式组件中,因为无法使用this,所以提出来hook形式解决
// useState 返回了一个数组,第一个参数是变量(响应式对象)名称,第二个是函数名,可以通过第二个函数更新这个变量
const [pageStart, setPageStart] = useState<number>(1);
const [pageSize, setPageSize] = useState<number>(10);
// 定义查询条件
const [params, setParams] = useState({});
// 发送请求 尝试发送请求
// 声明周期函数
// componentDidMount(){
// }
// useEffect是多个生命周期函数的集合,考虑在这里进行数据初始化/请求
// useEffect 第一个参数是函数类型,用于触发事件, 第二个参数是依赖于哪写数据的变化才触发
// 如果只希望在第一次进入的时候触发一次,那么第二个参数为[]数组
// useEffect componetDidMount componentDidUpdate componentWillUnmount
useEffect(() => {
dispatch({
type: `${namespace}/findArticleList`,
payload: {
start: pageStart,
limit: pageSize,
params,
},
});
}, [pageStart, pageSize, params]);
// 用于控制数据列
const columns = [
{
title: 'id',
dataIndex: 'id',
key: 'id',
},
{
title: '标题',
dataIndex: 'title',
key: 'title',
},
{
title: '作者',
dataIndex: 'author',
key: 'author',
},
{
title: '概要描述',
dataIndex: 'summary',
key: 'summary',
},
{
title: '创建时间',
dataIndex: 'createTime',
key: 'createTime',
},
];
// 比葫芦画瓢 找到form组件 定义了form的ref
const [form] = Form.useForm();
const onChange = (pageNumber: number, pSize?: number) => {
// 页面变化的时候触发 需要更改分页变化
// console.log('Page: ', pageNumber,pSize);
setPageStart(pageNumber);
setPageSize(pSize!);
};
// 查询的时候触发 如果需要刷新页面,本质需求是改变params对象 触发effect
const onSearch = (value: { title?: string; author?: string }) => {
// {author: 'zs', title: undefined} => {author: 'zs'}
let useParams = { ...value };
useParams = pickBy(useParams, (item) => item);
// console.log(useParams);
setParams({
...useParams,
});
};
const resetSearch = () => {
form.resetFields();
setParams({});
};
return (
<PageContainer>
<Card title="条件查询" style={{ width: '100%', marginBottom: '30px' }}>
<Form labelCol={{ span: 6 }} wrapperCol={{ span: 18 }} onFinish={onSearch} form={form}>
<Row gutter={32}>
<Col span={6}>
<Form.Item label="标题" name="title">
<Input />
</Form.Item>
</Col>
<Col span={6}>
<Form.Item label="作者" name="author">
<Input />
</Form.Item>
</Col>
</Row>
<Row gutter={32}>
<Col span={6} offset={18} style={{ textAlign: 'right' }}>
<Button onClick={resetSearch}>重置</Button>
{/* htmlType="submit" 把button变成表单默认提交按钮 用于触发onFinish */}
<Button type="primary" style={{ marginLeft: 30 }} htmlType="submit">
查询
</Button>
</Col>
</Row>
</Form>
</Card>
<Table
loading={loading}
pagination={{
showQuickJumper: true,
showSizeChanger: true,
current: pageStart,
pageSize,
total: totalCount,
onChange,
}}
rowKey="id"
dataSource={articleList}
columns={columns}
/>
;
</PageContainer>
);
};
// 绑定model和组件 把state映射到props
// 自定义的state不符合,但是可以合并connect.d.ts中的connectState
type StateType = {
[namespace]: MStateType;
} & ConnectState;
const mapStateToProps = (state: StateType) => ({
articleList: state[namespace].articleList,
totalCount: state[namespace].totalCount,
loading: state.loading.effects['article/findArticleList'] as boolean,
});
export default connect(mapStateToProps)(ArticleList);
总结: 分页查询和条件查询我们已经基本实现, 跟vue相比, useEffect 确实很方便 . 接下来我们实现文章的新增功能.