美文网首页
TablePro,一行代码搞定Filter+Table页面

TablePro,一行代码搞定Filter+Table页面

作者: 郁南 | 来源:发表于2020-07-02 22:11 被阅读0次

写这个题目有点标题党的嫌疑,但实际其实也相差无几,下面看真假

介绍

一般后台管理页面都会有增删改查,而增删改查就不可避免有搜索+Table展示。
为了避免写重复的代码,之前封装了Filter
组件,继而又封装TableProps,并整合在一起,就有了下面的TablePro

封装

  1. 先看TableProps的封装
/** 第三方库 */
import React, { memo, useState } from "react";

/** 第三方组件 */
import { Table } from "antd";

function areEqual(preProps, nextProps) {
  return preProps === nextProps;
}

const initPage = {
  current: 1,
  pageSize: 10
};

// 页面--代码
export default memo(
  ({
    rowKey,
    rowSelection,
    columns,
    dataSource,
    pagination,
    total,
    onPageChange,
    ...props
  }) => {
    const [pageParams, setPageParams] = useState(initPage);

    const onChange = (page, size) => {
      setPageParams({
        current: page,
        pageSize: size
      });
      onPageChange(page, size);
    };

    // 分页器
    const paginationProps = {
      ...pageParams,
      total,
      showSizeChanger: true,
      showQuickJumper: true,
      defaultPageSize: 10,
      hideOnSinglePage: false,
      pageSizeOptions: ["10", "20", "40"],
      onChange: (page, size) => onChange(page, size),
      onShowSizeChange: (page, size) => onChange(page, size),
      showTotal: () => (
        <span style={{ float: "left" }}>
          {`共 ${total} 条记录 第${pageParams.current}/${Math.ceil(
            total / pageParams.pageSize
          )}页`}
        </span>
      )
    };

    return (
      <Table
        {...props}
        rowSelection={rowSelection}
        pagination={pagination || paginationProps}
        rowKey={rowKey || "id"}
        columns={columns}
        dataSource={dataSource || []}
      />
    );
  },
  areEqual
);

上面只是基于日常需求的简单封装,但相信也能满足大部分场景了。

  1. 下面再结合SearchForm组件整合封装
/** 第三方库 */
import React from "react";
import { debounce } from "lodash"; // 防抖

/** 第三方组件 */
import { Spin } from "antd";

import { SearchForm } from "@/components";
import TableProps from "./TableProps";

// 页面--代码
export default ({
  extra, // 额外内容,如外标签等,ReactNode类型
  reset = true, // 是否需要重置按钮
  autoSearch, // 是否自动触发搜索
  loading, // loading 效果
  rowKey, // table的rowkey
  filterParams, // 查询条件,具体查看SearchForm
  total, // table的total
  columns, // table的columns
  dataSource, // table的dataSource
  rowSelection, // table的rowSelection
  onSearch, // 点击查询按钮
  stopPagination, // 是否符合查询条件,可以用来disabled分页器
  onPageChange, // 分页器change事件
  ...moreProps
}) => {
  return (
    <Spin spinning={loading} tip="Loading...">
      <SearchForm
        reset={reset}
        extra={extra}
        autoSearch={autoSearch}
        searchList={filterParams}
        stopPagination={debounce(e => stopPagination && stopPagination(e), 350)}
        onSearch={debounce(e => onSearch && onSearch(e), 350)}
        {...moreProps}
      />

      <TableProps
        rowKey={rowKey || "id"}
        total={total}
        columns={columns}
        dataSource={dataSource}
        rowSelection={rowSelection}
        onPageChange={(page, size) => onPageChange && onPageChange(page, size)}
        {...moreProps}
      />
    </Spin>
  );
};

如果看过之前的SearchForm封装Antd搜索栏组件SearchForm的封装/使用,会看见当前的SearchForm多了extra参数,这个extra是为了在搜索栏的搜索/重置后添加新的如别的按钮等功能的。

使用

/** 第三方库 */
import React, { useState, useEffect } from "react";
import { connect } from "dva"; 

/** 第三方组件 */
import { message } from "antd";
 
import TablePro from "@/components/Table/TablePro";
import redirect from "@/utils/redirect";
import { mobilePattern } from "@/utils/pattern";

import { searchList, columns } from "./initData";

const initPage = {
  pageNum: 1,
  pageSize: 10
};

// 原料类目页面--代码
export default connect(({ cashbacklist, loading }) => {
  return {
    ...cashbacklist,
    loading: !!loading.models.cashbacklist
  };
})(({ list, total, loading, dispatch }) => { 
  const [pageParams, setPageParams] = useState(initPage);

  useEffect(() => { 
    // eslint-disable-next-line no-use-before-define
    getList();
  }, [pageParams]);

  // 获取列表
  const getList = async () => {
    if (pageParams && pageParams.pageNum && pageParams.pageSize) {
      await dispatch({
        type: "cashbacklist/fetchList",
        payload: {
          ...pageParams
        }
      });
    }
  };

  /** 查询 */
  const onSearch = val => { 
    if (val.mobile && !mobilePattern.test(val.mobile)) {
      return message.error("请输入正确手机号码");
    }
    setPageParams({
      ...val,
      pageNum: pageParams.pageNum,
      pageSize: pageParams.pageSize
    });
  };

  // columns添加操作
  columns[6] = {
    title: "操作",
    dataIndex: "operate",
    key: "operate",
    render: (text, record) => {
      // console.log(text, record)
      const str = `formulaCode=${record.formulaCode}&userName=${
        record.userName
      }&mobile=${record.mobile}`;
      return (
        <a
          href="#"
          onClick={() => {
            const pageKey = Math.random();
            redirect({
              key: pageKey,
              name: "详情",
              path: `/xxx/xxx?${str}`
            });
          }}
          style={{ marginRight: "10px" }}
        >
          详情
        </a>
      );
    }
  };

  // 分页change
  const onPageChange = (page, size) => {
    setPageParams({
      pageNum: page,
      pageSize: size
    });
  };

  return ( 
      <TablePro
        rowKey="formulaId"
        loading={loading}
        filterParams={searchList}
        onSearch={e => onSearch(e)}
        onPageChange={(page, size) => onPageChange(page, size)}
        total={total}
        columns={columns}
        dataSource={list}
      /> 
  );
});

看最后的代码,如果不用组件封装的方式,代码量绝对在300行+。

当然这个组件还可以根据业务再次封装,甚至把接口请求等也封装进去,但我个人比较推崇组件纯净,所以我并没有封装具体的业务逻辑到TablePro中。

TablePro包括内部的SearchFormTableProps都只是简单的封装,当然还会有很多问题,比如性能优化、比如更好的需求兼容等等。
本文主要是提供一种思路,如果有更好的建议,欢迎在评论中指出。
感谢阅读~

相关文章

网友评论

      本文标题:TablePro,一行代码搞定Filter+Table页面

      本文链接:https://www.haomeiwen.com/subject/kyydqktx.html