文章目录
使用TS 封装 自定义hooks,实现不一样的 CRUD
这一篇主要是记录 查缺补漏,提升自己的 强Ts 使用能力,和对自定义hooks 的封装能力。
自定义 hooks
-
插入数据的 hook
- 完成插入数据的通用功能
- 获取表单数据
- 暴露出个性化定制数据的切面
- 调用插入数据的接口
- 提示插入成功
- 暴露出插入成功的回调
- 完成插入数据的通用功能
-
删除的 hook
- 完成删除数据的功能
- 确定好要删除数据的 id
- 调用 confirm 方法,提醒用户
- OK 的时候,调用接口,并提示成功
- 暴露出成功的回调
- 完成删除数据的功能
-
获取数据的 hook
- 获取到列表数据,以及筛选列表
- 确定好筛选参数
- 每次参数变化的时候,都需要调用一下列表接口
- 把拿到的列表数据返回出去
- 再暴露出修改参数的钩子
- 获取到列表数据,以及筛选列表
文件结构
type.ts
import { FormInstance } from "antd";
import { Key } from "antd/lib/table/interface";
import { IBasePagination } from "../type";
export interface IFetchListProps<Response> {
//每个页面获取数据的接口
API: (params: any) => Promise<IBasePagination<Response>>;
defaultParams?: Object
}
// 删除数据接口
export interface IDelData {
API: (ids: Key[]) => Promise<{}>;
title?: string;
success?: () => void
}
export interface IInsert<T> {
form: FormInstance<T>,
convertData?: (data: T) => T,
updateData?: (data: T) => void,
createData?: (data: T) => void,
success?: () => void,
getDetail?: (id: string) => Promise<T>,
convertDetailData?: (data: T) => T
}
useDelData.ts
import { useState } from "react";
import { IDelData } from "./type";
import { message, Modal } from "antd";
import { Key } from "antd/lib/table/interface";
const { confirm } = Modal;
export default function useDeldata(props: IDelData) {
const [ids, setIds] = useState<Key[]>([]);
const delData = (currentIds?: string[]) => {
confirm({
title: props.title || '确认删除该数据吗?',
async onOk() {
// 如果有 currentIds ,代表单删
// 如果没有 代表多删
await props.API(currentIds || ids);
message.success('删除成功');
props.success && props.success()
}
})
}
return {
ids,
setIds,
delData
}
}
使用
const { ids, setIds, delData } = useDeldata({
API: API.delUser,
success: () => {
setFilterParams({ ...filterParams, page: 1 })
}
})
<Button disabled={ids.length === 0} danger onClick={() => delData()}>删除</Button>
<Table
columns={columns}
dataSource={dataSource}
rowSelection={{
type: 'checkbox',
onChange: (keys) => {
setIds(keys);
}
}}>
</Table>
useFetchList.ts
import { useEffect, useState } from "react";
import { BasePageParams } from "../type";
import { IFetchListProps } from "./type";
export default function useFetchList<Response>(props: IFetchListProps<Response>) {
const [dataSource, setDataSource] = useState<Response[]>([]);
const [total, setTotal] = useState(0);
// 定义分页参数
const [filterParams, setFilterParams] = useState({ ...new BasePageParams(), ...(props.defaultParams || {}) });
/***
* 请求列表接口
* 拿到对应的 dataSource,total
* 传给后端
*/
useEffect(() => {
getData();
}, [filterParams])
// 获取数据
const getData = async () => {
const { list, pagination } = await props.API(filterParams);
list.forEach((item: any) => {
item.key = item.id;
})
setDataSource(list);
setTotal(pagination.total);
}
return {
dataSource,
total,
filterParams,
setFilterParams,
getData
}
}
使用
const { dataSource, total, filterParams, setFilterParams, getData } = useFetchList({
API: API.getUsers,
defaultParams: {
isback: true
}
})
<Table
columns={columns}
dataSource={dataSource}
rowSelection={{
type: 'checkbox',
onChange: (keys) => {
setIds(keys);
}
}}>
</Table>
<Button onClick={getData}>刷新</Button>
{/* 模糊搜索 */}
<Input
onChange={(e) => {
setFilterParams({
...filterParams,
page: 1,
username: e.target.value
} as any)
}}
placeholder="请输入用户名">
</Input>
useInsert.ts
// 负责新增和编辑的 hook
import { message } from "antd";
import { useEffect, useState } from "react";
import { IInsert } from "./type";
export default function useInsert<T>(props: IInsert<T>) {
const [isModal, setIsmodal] = useState(false);
// 关掉弹窗之后,需要清空表单数据
useEffect(() => {
if (!isModal) {
props.form.resetFields();
}
}, [isModal])
const handleOk = async () => {
// 获取表单里面的数据
let data = props.form.getFieldsValue(true);
// 对表单的数据进行转换
data = props.convertData ? props.convertData(data) : data;
// 调用后端接口
// 判断是编辑还是新增
data.id ?
props.updateData && (await props.updateData(data)) :
props.createData && (await props.createData(data))
// 暴露新的切面,也就是 insert 完成之后的一个回调
props.success && props.success();
// 弹窗
message.success(data.id ? '更新成功' : '创建成功');
setIsmodal(false);
}
// 回显表单数据的方法
const setDataInfo = async (id: string) => {
// 获取当前id的数据
let data = await props.getDetail!(id);
// 暴露出一个可以操作数据的方法
if (props.convertDetailData) {
(data as any) = props.convertDetailData(data);
}
// 给表单回显数据
props.form.setFieldsValue(data as any);
// 打开弹窗
setIsmodal(true);
}
return {
handleOk,
setIsmodal,
isModal,
setDataInfo
}
}
使用
const { handleOk, setIsmodal, isModal, setDataInfo } = useInsert({
form,
createData: API.createUser,
updateData: API.updateUser,
getDetail: API.getUserDetail,
success: () => {
setFilterParams({
...filterParams,
page: 1
})
}
})
<Button onClick={() => setDataInfo(item.id)}>编辑</Button >
部分的接口方法
import { Key } from 'antd/lib/table/interface';
import { IActivity, IActivityParams } from '../pages/activityManage/activityManage.type';
import { IBanner } from '../pages/bannerManage/bannerManage.type';
import { ILoginParams, ILoginResponse } from '../pages/login/Login.type';
import { IUser, IUserParams } from '../pages/registerUserCheck/registerUserCheck.type';
import { BasePageParams, IBasePagination } from '../type';
import request from '../utils/request';
// 如果业务复杂的话,可以分割模块,现在我们可以整个 api 作为一层
export default {
// 登陆
/**
* 第一个是接受的参数类型
* 第二个是返回的参数类型(看post函数源码得出的)
*/
login(data: ILoginParams) {
return request.post<ILoginParams, ILoginResponse>('/admin/base/open/login', data);
},
// 获取活动列表
getActivitys(data: IActivityParams) {
return request.post<IActivityParams, IBasePagination<IActivity>>(
"/admin/base/activityManage/page",
data
)
},
// 删除活动
delActivity(ids: Key[]) {
return request.post<Key[], {}>(
"/admin/base/activityManage/delete",
{ ids }
)
},
// 创建活动
createActivity(data: IActivity) {
return request.post<IActivity, {}>(
"/admin/base/activityManage/add", data)
},
// 更新活动
updateActivity(data: IActivity) {
return request.post<IActivity, {}>(
"/admin/base/activityManage/update", data)
},
// 获取详情
getActivityDetail(id: string) {
return request.get<string, IActivity>(`/admin/base/activityManage/info?id=${id}`)
},
}
由于篇幅原因,只贴了部分的代码
具体项目代码地址在这哦:
https://github.com/okAlr/Ts-hooks-Demo
欢迎指出错误