react封装 ant table form分页

实现常规的form table 分页的封装

说明:根据项目情况更改分页参数useCommonHook文件中的pageObj 参数和BaseTable用到的分页参数

useCommonHook文件中如果没有使用@reduxjs/toolkit可以改为

yarn add nanoid

然后import { nanoid } from “nanoid”;

一定要使用nanoid不然无法刷新 或者用时间戳

  1. 示例用法 组件用法
import { axios } from "@/common/request";
import { Space } from "antd";
import BaseTable from "@/components/BaseTable";
import { Form, Input, Button, Modal } from "antd";
import { useState } from "react";
const columns = [
  {
    title: "主单号",
    dataIndex: "cgid",
  },
  {
    title: "分单号",
    dataIndex: "SubOrderNo",
  },
  {
    title: "货物RFID",
    dataIndex: "Cargorfid",
  },

  {
    title: "Action",
    key: "action",
    render: (text, record) => (
      <Space size="middle">
        <a>Invite {record.Status}</a>
        <a>Delete</a>
      </Space>
    ),
  },
];

// 表单搜索
const formItem = [
  <Form.Item className="baseTable_form_item" label="姓名" name="username">
    <Input />
  </Form.Item>,
  <Form.Item className="baseTable_form_item" label="年纪" name="age">
    <Input />
  </Form.Item>,
  <Form.Item className="baseTable_form_item" label="学校" name="school">
    <Input />
  </Form.Item>,
  <Form.Item className="baseTable_form_item" label={<Input />} name="school">
    <Input />
  </Form.Item>,
];
// 刷新(保持搜索条件和分页): refresh(false)    重置:refresh(true)
let refresh = null;
const Home = () => {
  const [modelShow, setModelShow] = useState(false);
  // 表格接口 不要在请求接口里面setState
  const getList = (params = { pageindex: 0, pagesize: 30 }, tableRefresh) => {
      refresh = tableRefresh;
      return axios.get("/api/sinoapi/getcargolist", {
        pageindex: 0,
        pagesize: 30,
        ...params,
      });
    },
    // 接口请求成功后对数据的修改 不要在complete接口里面setState
    complete = (list) => {
      // 例如
      list.forEach((item) => {
        item.name = item.name + item.age;
      });
      return list;
    };
  // formProps:form的其他props属性(参考ant form)  tableProps: table的其他props属性(参考ant table)
  return (
    <>
      <BaseTable
        formItem={formItem}
        initialValues={{ username: "ss" }}
        formProps={{}}
        search={getList}
        complete={complete}
        columns={columns}
        tableProps={{
          rowKey: "Cargorfid",
        }}
      >
        {/* 操作按钮 */}
        <Button
          type="primary"
          onClick={() => {
            setModelShow(true);
          }}
        >
          导出
        </Button>
        <Button type="primary">导出</Button>
        <Button type="primary">导出</Button>
        <Button type="primary">导出</Button>
        <Button type="primary">导出</Button>
        <Button type="primary">导出</Button>
      </BaseTable>
      {/* 模态框 */}
      <Modal
        title="Basic Modal"
        visible={modelShow}
        onOk={() => {
          refresh(true);
          setModelShow(false);
        }}
        onCancel={() => {
          refresh(false);
          setModelShow(false);
        }}
      >
        <p>Some contents...</p>
        <p>Some contents...</p>
        <p>Some contents...</p>
      </Modal>
    </>
  );
};

export default Home;

  1. 封装的BaseTable 组件
import classNames from "classnames";
import { Form, Button, Table, Pagination } from "antd";
import "./index.less";
import {
  useFormItemKey,
  useButtonMargin,
  useTableAxios,
} from "./useCommonHook";

// import { selectBreadCrumbs } from "@/redux/reducer/permissions"; 
// import { useSelector } from "react-redux";
import { useCallback, useState } from "react";

const BaseTable = ({
  formItem = [],
  initialValues = {},
  formProps = {},
  search,
  columns = [],
  tableProps = {},
  children,
  complete = null,
}) => {
  // =======================================form相关==============================
  // form 实例
  const [form] = Form.useForm();
  // 手动添加key防止报错
  const [formItemKeys] = useFormItemKey(formItem);
  // 添加按钮margin
  const [childrenMargin] = useButtonMargin(children);
  // =======================================表格相关===============================
  const [loading, setLoading] = useState(false);
  const tableRefresh = useCallback((form, dispatch) => (refresh) => {
    if (refresh) {
      form.resetFields();
      dispatch({ type: "reset" });
      return;
    }
    dispatch({ type: "refresh" });
  });
  const searchCommon = (values, params, dispatch, setList) => {
    setLoading(true);
    search({ ...values, ...params }, tableRefresh(form, dispatch))
      .then(({ success, result }) => {
        setLoading(false);
        if (!success) return;
        if (complete) {
          const arrs = complete(result?.data ?? []);
          setList(arrs);
        }
        setList(result?.data ?? []);

        dispatch({ type: "total", payload: result?.total ?? 0 });
      })
      .catch((e) => {
        console.log("=======列表请求失败========" + e);
        setLoading(false);
      });
  };

  const [list, dispatch, params, setList] = useTableAxios(form, searchCommon);

  const paginationChange = useCallback((page, pageSize) => {
    dispatch({ type: "pageindex", payload: page });
    dispatch({ type: "pagesize", payload: pageSize });
  });
  const onFinish = useCallback((values) => {
    searchCommon(values, params, dispatch, setList);
  });
  return (
    <div>
      <div className={classNames("baseTable_padding", "baseTable_form")}>
       {/* <span style={{ color: "rgba(0, 0, 0, 0.45)" }}>
          {useSelector(selectBreadCrumbs) || null}
        </span> */}
        <Form
          initialValues={{ ...initialValues }}
          form={form}
          name="basicForm"
          labelCol={{ span: 8 }}
          wrapperCol={{ span: 16 }}
          onFinish={onFinish}
          autoComplete="off"
          layout="inline"
          {...formProps}
        >
          {formItemKeys}
          <Form.Item
            wrapperCol={{ offset: 8, span: 16 }}
            className="baseTable_form_item"
          >
            <Button type="primary" htmlType="submit">
              搜索
            </Button>
          </Form.Item>
          <Form.Item
            wrapperCol={{ offset: 8, span: 16 }}
            className="baseTable_form_item"
          >
            <Button
              htmlType="button"
              onClick={() => {
                tableRefresh(form, dispatch)(true);
              }}
            >
              重置
            </Button>
          </Form.Item>
        </Form>
      </div>
      <div style={{ padding: "15px" }}>{childrenMargin}</div>
      <div className={classNames("baseTable_padding", "baseTable_form")}>
        <Table
          columns={columns}
          dataSource={list}
          pagination={false}
          loading={loading}
          {...tableProps}
        />
        <Pagination
          className="baseTable_pagination"
          showTotal={(total) => `${total}`}
          showQuickJumper
          current={params.pageindex}
          total={params.total}
          onChange={paginationChange}
        />
      </div>
    </div>
  );
};

export default BaseTable;

  1. 用得到的自定义useCommonHook
import { useState, useEffect, cloneElement, Children, useReducer } from "react";
// 或者 yarn add nanoid  import { nanoid } from "nanoid";
import { nanoid } from "@reduxjs/toolkit";

// 给Form.Item 添加key
export const useFormItemKey = (formItem) => {
  const [formItemKeys, setFormItemKeys] = useState([]);
  useEffect(() => {
    // const result = formItem.map((item) =>
    //   cloneElement(item, { key: nanoid() })
    // );

    const result = Children.map(formItem, (item) =>
      cloneElement(item, { key: nanoid() })
    );

    setFormItemKeys(result);
  }, [formItem]);
  return [formItemKeys];
};

// 给操作按钮添加margin
export const useButtonMargin = (children) => {
  const [childrenMargin, setchildrenMargin] = useState([]);
  useEffect(() => {
    const result = Children.map(children, (item) =>
      cloneElement(item, { key: nanoid(), style: { marginRight: "15px" } })
    );

    setchildrenMargin(result);
  }, [children]);
  return [childrenMargin];
};

export const pageObj = {
  pageindex: 1,
  pagesize: 10,
  total: 0,
  reset: nanoid(),
};

export const reducer = (state, action) => {
  switch (action.type) {
    case "total":
      return { ...state, total: action.payload };
    case "pageindex":
      return { ...state, pageindex: action.payload };
    case "pagesize":
      return { ...state, pagesize: action.payload };
    case "reset":
      return { ...state, ...pageObj, reset: nanoid() };
    case "refresh":
      return { ...state, reset: nanoid() };
  }
};

// 表格分页hook
export const useTableAxios = (form, searchCommon) => {
  const [list, setList] = useState([]);
  // 分页参数
  const [params, dispatch] = useReducer(reducer, pageObj);
  useEffect(() => {
    const timeout = setTimeout(() => {
      const values = form.getFieldsValue();
      searchCommon(values, params, dispatch, setList);
    }, 0);
    return () => {
      clearTimeout(timeout);
    };
  }, [params.pageindex, params.pagesize, params.reset]);
  return [list, dispatch, params, setList];
};

  1. 依赖的css index.less
.baseTable_form {
  background: white;
}
.baseTable_padding {
  padding: 0px 15px 15px 15px;
}
.baseTable_form_item {
  margin-top: 15px;
}

.baseTable_pagination {
  margin-top: 15px;
  text-align: right;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值