react+ts自定义hook:antd表格+模态框增删改查

useTable_crud.ts

import { useEffect, useState, Key } from 'react';
import { showMessage } from 'common/props/messageProps';
import axios from 'axios';
import {
  ChangeDataParams,
  UseGetTableProps,
  changePageType,
  changeSelectType,
  getDeleteNumType,
  handleChangeDataParams,
  handleCrudParams,
  onTableRowSelectType,
  recordType,
} from '../type';
import { CustomPagination } from 'common/props/tableProps';
import { useDidUpdateEffect } from 'common/hooks/useDidUpdateEffect';
import { getTableRowSelection } from 'common/props/tableProps/rowSelection';
import { axiosData } from 'common/hooks/axios';
//T:表格数据类型 U:参数类型
const useGetTable = <T, U = {}>(props: UseGetTableProps<U>) => {
  //url:接口路径,params:参数,isUseDidUpdateEffect:是否初次加载,type:(1:get 分页(默认)  2:get 不分页 3.post 分页 4.post 不分页)
  const { url, params, isUseDidUpdateEffect, type = 1 } = props;
  const [tableLoading, setTableLoading] = useState(false); //表格加载状态
  const [tableData, setTableData] = useState<T[]>([]); //表格数据
  const [tableTotal, setTableTotal] = useState(0); //表格总数
  const [current, setCurrent] = useState<number>(1); //当前是第几页
  const [pageSize, setPageSize] = useState<number>(10); //一页展示多少
  const [searchValue, setSearchValue] = useState<recordType>(); //搜索框搜索的值
  const [selectedRowKeys, setSelectRowKeys] = useState<Key[]>([]); //表格勾选的key
  const [selectedRows, setSelectedRows] = useState<T[]>([]); //表格勾选的数据
  const [recordData, setRecordData] = useState<T | {}>({}); //打开模态框的记录
  const [crudType, setCrudType] = useState<number>(2); //模态框的类型 0:修改 1:新建 2:查看
  const [isShowModal, setIsShowModal] = useState(false); //是否打开模态框
  const [modalTitle, setModalTitle] = useState(''); //模态框的表头
  const tableDataParams = [searchValue, current, pageSize];
  //勾选
  const changeSelect: changeSelectType<T> = (selectedRowKeys, selectedRows) => {
    setSelectRowKeys(selectedRowKeys);
    setSelectedRows(selectedRows);
  };
  //改变页数
  const changePage: changePageType = (current, pageSize) => {
    setCurrent(current);
    setPageSize(pageSize);
  };
  //重置勾选
  const resetSelect = () => {
    setSelectRowKeys([]);
    setSelectedRows([]);
  };
  //表单数据
  const getSearchValue = (v: recordType) => {
    setSearchValue(v);
    setCurrent(1);
  };
  //根据类型获取表格数据
  const getTableData = async () => {
    try {
      setTableLoading(true);
      const parament = { ...searchValue, ...params, current, pageSize };
      if (type === 1) {
        const { data } = await axios.get(url, {
          params: parament,
        });
        setTableData(data.data);
        setTableTotal(data.total);
      } else if (type === 2) {
        const { data } = await axios.get(url, { params: { ...searchValue, ...params } });
        if (data.code) {
          setTableData(data.data);
          setTableTotal(data.data.length);
        } else {
          setTableData(data);
          setTableTotal(data.length);
        }
      } else if (type === 3) {
        const { data } = await axios.post(url, { ...parament });
        setTableData(data.data);
        setTableTotal(data.total);
      } else if (type === 4) {
        const { data } = await axios.post(url, { ...searchValue, ...params });
        setTableData(data);
        setTableTotal(data.length);
      }
    } catch (error) {
      showMessage('error', (error as Error).message);
    } finally {
      setTableLoading(false);
    }
  };
  //重新加载表格数据数据和重置操作
  const reloadData = () => {
    getTableData();
    resetSelect();
  };
  const tablePagination = { ...CustomPagination(current, pageSize, tableTotal), onChange: changePage }; //table 分页
  //table 勾选
  const tableSelect = {
    onChange: changeSelect,
    selectedRowKeys,
    selectedRows,
    preserveSelectedRowKeys: true,
  };
  //loading 和table数据
  const LoadingAndData = {
    spinning: tableLoading,
    dataSource: tableData,
  };
  //message的类型
  const messageMethod = (v: boolean) => {
    return v ? 'success' : 'error';
  };
  //删除
  const handleDelete: ChangeDataParams = async (url, params, num, method = 'post') => {
    axiosData(url, params, method).then((res) => {
      const method = messageMethod(res.success);
      if (res.success) {
        reloadData();
        getDeleteNum(num);
      }
      showMessage(method, res.message);
    });
  };
  //创建/修改/复制调用接口 url:接口路径,params:接口参数,method:请求方式
  const handleChangeData: handleChangeDataParams = async (url, params, method = 'post') => {
    axiosData(url, params, method).then((res) => {
      const method = messageMethod(res.success);
      if (res.success) {
        handleCancel();
        reloadData();
      }
      showMessage(method, res.message);
    });
  };
  //增删查 打开modal操作  record:当前点击的记录,title:打开的弹窗的标题,crudType:0:修改 1 新建 2查看
  const handleCrud: handleCrudParams = (record, title, crudType) => {
    setModalTitle(title);
    setRecordData(record);
    setCrudType(crudType);
    setIsShowModal(true);
  };
  //关闭模态框
  const handleCancel = () => {
    setIsShowModal(false);
  };
  //获取删除后的current
  const getDeleteNum: getDeleteNumType = (num) => {
    let updatedCurrent = 1;
    if (current !== 1) {
      updatedCurrent = Math.ceil((tableTotal - (num ? num : selectedRowKeys.length)) / pageSize); // 更新后的当前页码
      setCurrent(updatedCurrent);
    }
  };
  //行选
  const onTableRowSelect: onTableRowSelectType<T> = (record, recordKey) => {
    const OnRowSelectKeys = getTableRowSelection(selectedRowKeys, recordKey);
    const OnRowSelectRows = getTableRowSelection(selectedRows, record);
    setSelectRowKeys(OnRowSelectKeys);
    setSelectedRows(OnRowSelectRows);
  };
  //是否初次加载
  const effectCallback = () => {
    getTableData();
  };
  isUseDidUpdateEffect ? useDidUpdateEffect(effectCallback, tableDataParams) : useEffect(effectCallback, tableDataParams);
  return {
    tablePagination,
    tableSelect,
    LoadingAndData,
    getSearchValue,
    reloadData,
    getDeleteNum,
    onTableRowSelect,
    tableTotal,
    searchValue,
    tableData,
    setTableData,
    handleDelete,
    handleChangeData,
    handleCrud,
    recordData,
    crudType,
    isShowModal,
    handleCancel,
    modalTitle,
  };
};
export default useGetTable;

type.ts

import { Key } from 'react';
export type changePageType = (current: number, pageSize: number) => void;
export type changeSelectType<T> = (selectedRowKeys: React.Key[], selectedRows: T[], info: { type: string }) => void;
export type recordType = Record<string, unknown>;
export type UseGetTableProps<U = {}> = {
  url: string;
  params?: U;
  isUseDidUpdateEffect?: boolean;
  type?: number;
};
type HttpMethod = 'get' | 'post' | 'put' | 'delete';
export type handleCrudParams = (record: recordType, title: string, crudType: number) => void;
export type ChangeDataParams = (url: string, params: recordType, num?: number, method?: HttpMethod) => void;
export type handleChangeDataParams = (url: string, params: recordType, method?: HttpMethod) => void;
export type onTableRowSelectType<T> = (record: T, recordKey: Key) => void;
export type getDeleteNumType = (num?: number) => void;

CustomPagination

import { Table, TablePaginationConfig, PaginationProps, Typography } from 'antd';
const { Link } = Typography;

//勾选框的操作
export const CustomRowSelection = {
  selections: [Table.SELECTION_ALL, Table.SELECTION_INVERT, Table.SELECTION_NONE],
  preserveSelectedRowKeys: true,
};
//页码
export const CustomPageSize = ['10', '25', '50', '100'];
//分页
const itemRender: PaginationProps['itemRender'] = (_, type, originalElement) => {
  const style = {
    background: '#ffffff',
    border: '1px solid #ddd',
    minWidth: 70,
    borderRadius: 6,
    height: 32,
    display: 'block',
  };
  const LinkType = (v: string) => (
    <Link style={{ ...style, position: 'relative' }} className="pageLink">
      <span style={{ position: 'absolute', top: '50%', transform: 'translate(-50%,-50%)', width: '100%' }}>{v}</span>
    </Link>
  );
  if (type === 'prev') {
    return LinkType('上一页');
  }
  if (type === 'next') {
    return LinkType('下一页');
  }
  return originalElement;
};
export type CustomPaginationConfig = (current: number, pageSize: number, total: number) => TablePaginationConfig;
export const CustomPagination: CustomPaginationConfig = (current, pageSize, total) => {
  return {
    itemRender,
    current,
    pageSize,
    total,
    defaultPageSize: 10,
    showSizeChanger: true,
    pageSizeOptions: CustomPageSize,
    showQuickJumper: true,
    responsive: true,
  };
};
export const stopPropagation = (e: React.MouseEvent<HTMLElement, MouseEvent> | undefined) => e?.stopPropagation();

useDidUpdateEffect

import { DependencyList, useEffect, useRef } from 'react';

export const useDidUpdateEffect = (fn: { (): void; (): void; }, inputs: DependencyList | undefined) => {
  const didMountRef = useRef(false);
  useEffect(() => {
    if (didMountRef.current) fn();
    else didMountRef.current = true;
  }, inputs);
};

getTableRowSelection

//行选
export const getTableRowSelection = <T>(OnRowSelectKeys: T[], recordKey: T) => {
  const updatedRowKeys = [...OnRowSelectKeys];
  const selectedIndex = updatedRowKeys.indexOf(recordKey);

  if (selectedIndex >= 0) {
    updatedRowKeys.splice(selectedIndex, 1);
  } else {
    updatedRowKeys.push(recordKey);
  }

  return updatedRowKeys;
};

axiosData

import { showMessage } from 'common/props/messageProps';
import axios, { AxiosRequestConfig } from 'axios';
import { HttpMethod } from '../table/type';
export const axiosData = async <I>(url: string, params: I & AxiosRequestConfig<I>, method: HttpMethod = 'post') => {
  try {
    const { status, data } = await axios[method](url, params);
    if (status === 200) {
      return data;
    }
  } catch (error) {
    showMessage('error', (error as Error).message);
  }
};

showMessage

import { message } from 'antd';
//类型 内容 持续时间
export const showMessage = (type: 'success' | 'error' | 'info' | 'warning', content: string, duration = 3): void => {
  message.open({
    type,
    content,
    duration,
  });
};
//未勾选
export const notSelectMessage = () => {
  showMessage('info', '请选择一条要操作的数据');
};

主要使用useTable_crud.ts 里导出的数据 比如表格的勾选分页,数据和loading,模态的打开状态,初始化数据,增删改查的函数等

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
很抱歉,我是一名AI语言模型,无法使用代码进行编程,以下是一个使用mock react ts hooks做增删改查的示例: ``` import React, { useState } from 'react'; import { v4 as uuidv4 } from 'uuid'; interface Todo { id: string; title: string; completed: boolean; } const initialTodos: Todo[] = [ { id: uuidv4(), title: 'Learn React', completed: false }, { id: uuidv4(), title: 'Learn TypeScript', completed: false }, { id: uuidv4(), title: 'Build a Todo App', completed: false }, ]; const App: React.FC = () => { const [todos, setTodos] = useState<Todo[]>(initialTodos); const [newTodo, setNewTodo] = useState<string>(''); const handleNewTodoChange = (event: React.ChangeEvent<HTMLInputElement>) => { setNewTodo(event.target.value); }; const handleAddTodo = () => { if (newTodo.trim() !== '') { setTodos([...todos, { id: uuidv4(), title: newTodo, completed: false }]); setNewTodo(''); } }; const handleDeleteTodo = (id: string) => { setTodos(todos.filter(todo => todo.id !== id)); }; const handleToggleTodo = (id: string) => { setTodos( todos.map(todo => todo.id === id ? { ...todo, completed: !todo.completed } : todo, ), ); }; const handleEditTodo = (id: string, newTitle: string) => { setTodos( todos.map(todo => (todo.id === id ? { ...todo, title: newTitle } : todo)), ); }; return ( <div> <h1>Todo App</h1> <input type="text" value={newTodo} onChange={handleNewTodoChange} /> <button onClick={handleAddTodo}>Add Todo</button> <ul> {todos.map(todo => ( <li key={todo.id}> <input type="checkbox" checked={todo.completed} onChange={() => handleToggleTodo(todo.id)} /> <input type="text" value={todo.title} onChange={event => handleEditTodo(todo.id, event.target.value)} /> <button onClick={() => handleDeleteTodo(todo.id)}>Delete</button> </li> ))} </ul> </div> ); }; export default App; ``` 在这个示例中,我们定义了一个`Todo`类型,它包含一个`id`、一个`title`和一个`completed`属性。我们使用`useState`钩子来管理一个`todos`数组和一个`newTodo`字符串,`todos`数组包含所有的todo项,`newTodo`字符串保存用户输入的新todo项的标题。 我们使用`handleNewTodoChange`函数来处理新todo标题的变化。当用户在输入框中输入新标题时,我们使用`setNewTodo`来更新`newTodo`的值。 当用户点击“添加Todo”按钮时,我们使用`handleAddTodo`函数来添加新的todo项。如果`newTodo`不是空字符串,我们将一个新的`Todo`对象添加到`todos`数组中,并将`newTodo`设置为空字符串。 当用户点击“删除”按钮时,我们使用`handleDeleteTodo`函数来删除todo项。我们使用`setTodos`和`filter`方法来过滤掉与传递的id相匹配的todo项。 当用户切换复选框时,我们使用`handleToggleTodo`函数来切换todo项的完成状态。我们使用`setTodos`和`map`方法来更新与传递的id相匹配的todo项的完成状态。 当用户编辑todo项的标题时,我们使用`handleEditTodo`函数来更新todo项的标题。我们使用`setTodos`和`map`方法来更新与传递的id相匹配的todo项的标题。 最后,我们在render函数中渲染了一个todo列表,包含每个todo项的复选框、文本框、删除按钮和编辑按钮。当用户切换复选框时,我们调用`handleToggleTodo`函数。当用户编辑文本框中的标题时,我们调用`handleEditTodo`函数。当用户点击“删除”按钮时,我们调用`handleDeleteTodo`函数。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值