使用TS 封装 自定义hooks,实现不一样的 CRUD

使用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

欢迎指出错误

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值