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

news2024/11/15 7:35:25

文章目录

  • 使用TS 封装 自定义hooks,实现不一样的 CRUD
    • 自定义 hooks
    • 文件结构
      • type.ts
      • useDelData.ts
        • 使用
      • useFetchList.ts
        • 使用
      • useInsert.ts
        • 使用
      • 部分的接口方法

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

欢迎指出错误

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/60016.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

三、内存管理 (一)存储器管理

目录 1.1程序运行的基本过程 1.1.1 编辑、编译、链接、装入 1.1.2链接的三种方式 1.1.3装入的三种方式 1.2内存管理基本概念 1.2.1内存保护 1.2.2内存空间扩充 1.2.3地址转换功能 1.2.4内存空间的分配与回收 1.2.4.1连续分配管理方式 1.2.4.1.1单一连续分配 1.2.4.1…

Http协议和Https协议

Http是不安全的&#xff0c;你的数据容易被黑客拦截&#xff0c;篡改&#xff0c;攻击 https要求对数据加密&#xff08;不能明文传输&#xff09;, 用抓包工具抓http请求&#xff0c;抓出来的都是明文的&#xff0c;你能看得懂的&#xff0c;抓https请求&#xff0c;抓出来的…

网站域名被QQ拦截提示:当前网页非官方页面拦截的解决办法

今天网友提醒&#xff0c;星空站长网的链接被QQ屏蔽拦截了。提示&#xff1a;当前页面非官方页面&#xff0c;请复制到浏览器打开。 如图&#xff1a; 原因&#xff1a;这是因为QQ方面的诈骗信息特别多&#xff0c;所以腾讯官方索性就直接屏蔽了所有的外部链接。让站长们通过申…

Python源码剖析笔记1-整数对象PyIntObject

1、PyIntObject 对象 [intobject.h] typedef struct {PyObject_HEADlong ob_ival; } PyIntObjectPyIntObject是一个不可变&#xff08;immutable&#xff09;对象。Python内部也大量的使用整数对象&#xff0c;我们在自己的代码中也会有大量的创建销毁整型对象的操作&#xff…

SVM 用于将数据分类为两分类或多分类(Matlab代码实现)

&#x1f468;‍&#x1f393;个人主页&#xff1a;研学社的博客 &#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜…

CMake中install的使用

CMake中的install命令用于指定安装时要运行的规则&#xff0c;其格式如下&#xff1a; install(TARGETS targets... [EXPORT <export-name>][RUNTIME_DEPENDENCIES args...|RUNTIME_DEPENDENCY_SET <set-name>][[ARCHIVE|LIBRARY|RUNTIME|OBJECTS|FRAMEWORK|BUNDL…

基于单片机的电压电流表设计

原理图&#xff1a; 部分程序&#xff1a; #include "stc15.h" #include "delay.h" #include "timer.h" #include "TM7707.h" #include "LCD1602.h" #include "eeprom.h" #include "stdio.h" #include…

【数学】双根号求值域问题

∣双根号求值域问题NightguardSeries.∣\begin{vmatrix}\Huge{\textsf{ 双根号求值域问题 }}\\\texttt{ Nightguard Series. }\end{vmatrix}∣∣∣∣∣​ 双根号求值域问题 Nightguard Series. ​∣∣∣∣∣​ 求 f(x)3x−63−xf(x)\sqrt{3x-6}\sqrt{3-x}f(x)3x−6​3−x​ 的…

开发工具——gdb

开发工具gdb gdb在Linux下负责程序的调试。 gdb相较于vs2019的调试&#xff0c;是不方便的。图形化界面调试确实是一种进步的现象。 先编写一个简单的程序&#xff0c;如果不支持在for循环中定义变量&#xff0c;要在编译指令后面加上-stdc99选项。 要编译的文件和要生成的文…

Spring 源码编译

Spring 源码编译&#xff0c;一定要选好版本&#xff01;&#xff01;&#xff01; Spring 源码编译&#xff0c;一定要选好版本&#xff01;&#xff01;&#xff01; Spring 源码编译&#xff0c;一定要选好版本&#xff01;&#xff01;&#xff01; 重要的事说三遍。 Spri…

MYSQL用函数请三思

背景&#xff1a;最近公司有个同事遇到个需求需要用到mysql sleep函数&#xff0c;但结果却大出意料. 测试如下&#xff1a; 表&#xff1a; CREATE TABLE test_sleep ( id int NOT NULL AUTO_INCREMENT, a int NOT NULL, b int NOT NULL, PRIMARY KEY (id), KEY a (a) ) ENGIN…

电子学会2021年3月青少年软件编程(图形化)等级考试试卷(一级)答案解析

青少年软件编程&#xff08;图形化&#xff09;等级考试试卷&#xff08;一级&#xff09; 分数&#xff1a;100.00 题数&#xff1a;37 一、单选题&#xff08;共25题&#xff0c;每题2分&#xff0c;共50分&#xff09; 1. 花花幼儿园有三个班。根据下面三句话&…

CentosLinux 7 字符安装教程

打开VMware虚拟机,点击文件 — 新建虚拟机选项。在弹出的对话框中选择自定义(高级)选项。单机下一步。 以下步骤根据自己的所需自行配置

[附源码]Python计算机毕业设计Django酒店在线预约咨询小程序

项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等等。 环境需要 1.运行环境&#xff1a;最好是python3.7.7&#xff0c;…

健身中心管理系统/健身房管理系统

摘 要 随着信息技术和网络技术的飞速发展&#xff0c;人类已进入全新信息化时代&#xff0c;传统管理技术已无法高效&#xff0c;便捷地管理信息。为了迎合时代需求&#xff0c;优化管理效率&#xff0c;各种各样的管理系统应运而生&#xff0c;各行各业相继进入信息管理时代&…

【OpenCV-Python】教程:3-16 利用Grabcut交互式前景提取

OpenCV Python Grabcut分割 【目标】 Grabcut 算法创建一个交互程序 【理论】 从用户角度是如何工作的呢&#xff1f;用户在需要的目标上初始绘制一个矩形&#xff0c;前景目标必须完全在矩形内部&#xff0c;算法迭代的去分割然后得到更好的效果&#xff0c;但是有些情况下…

Java9-17新特性解读,了解少于3个你可能脱节了

前言 Java8出来这么多年后&#xff0c;已经成为企业最成熟稳定的版本&#xff0c;相信绝大部分公司用的还是这个版本&#xff0c;但是一眨眼今年Java19都出来了&#xff0c;相信很多Java工程师忙于学习工作对新特性没什么了解&#xff0c;有的话也仅限于某一块。 本篇就是博主对…

【论文笔记】Radatron: Accurate Detection Using Multi-Resolution Cascaded MIMO Radar

文章及补充材料链接&#xff1a;https://jguan.page/Radatron/ 理解本文需要一些电磁波与雷达信号处理相关的理论知识。 1. 引言 雷达的角度分辨率通常很低。雷达的角度分辨率与雷达的天线孔径成反比&#xff0c;因此毫米波雷达要达到激光雷达的角度分辨率&#xff0c;需要3000…

黑盒测试用例设计 - 因果图法

说明 因果图法是一种适合于描述对多种输入条件组合的测试方法根据输入条件的组合、约束关系和输出条件的因果关系&#xff0c;分析输入条件的各种组合情况&#xff0c;从而设计测试用例的方法它适合于检查程序输入条件涉及的各种组合情况 使用步骤 第一步&#xff1a;根据功…

60岁首席工程师被SpaceX边缘化,主管:我怕他退休或死了

金磊 发自 凹非寺量子位 | 公众号 QbitAI在SpaceX&#xff0c;连首席工程师竟也能遭遇职场边缘化。故事的主人公叫做John Johnson&#xff08;姑且叫他“逊哥”&#xff09;&#xff0c;他在2018年加入SpaceX。当时的逊哥已经58岁&#xff0c;但在光学工程领域可谓颇有建树。刚…