[Hook]useTable

后台管理系统中必定会出现的组件就是表格页面,并且一个系统中往往有多个表格页面。
表格页面的业务逻辑,有许多相似之处,包括:

  1. 获取数据源
  2. 刷新数据源
  3. 分页
  4. 查询
  5. loading

因此,我发现在重构之前,每一个表格页面,都有一套几乎一模一样的逻辑:

import { Table } from "antd";
import { mock, Random } from "mockjs";
import React, { useEffect, useState } from "react";

const fetchUsers = (pageIndex, pageSize) => {
  return Promise.resolve(
    mock({
      "total|10-100": pageSize * 5.5,
      "list|10": [
        {
          "name|1": [
            Random.name(),
            Random.name(),
            Random.name(),
            Random.name(),
          ],
          "gender|1": ["male", "female"],
        },
      ],
    })
  );
};

const UserList = () => {
  const [isLoading, setIsLoading] = useState(false);
  const [dataSource, setDataSource] = useState([]);
  const [pageIndex, setPageIndex] = useState(10);
  const [pageSize, setPageSize] = useState(10);
  const [total, setTotal] = useState(0);

  useEffect(() => {
    fechDataSource();
  }, []);

  useEffect(() => {
    fechDataSource();
  }, [pageSize, pageIndex]);

  const fechDataSource = () => {
    setIsLoading(true);
    fetchUsers(pageIndex, pageSize)
      .then((res) => {
        setDataSource(res.list);
        setTotal(res.total);
      })
      .catch((error) => {
        console.error(error);
      })
      .finally(() => {
        setIsLoading(false);
      });
  };

  const pagination = {
    showSizeChanger: true,
    showTotal: () => `total: ${total}`,
    total,
    current: pageIndex,
    pageSize,
    onChange: (pageIndex, pageSize) => {
      setPageIndex(pageIndex);
      setPageSize(pageSize);
    },
  };

  const tableProps = {
    loading: isLoading,
    dataSource,
    columns: [
      {
        title: "Name",
        dataIndex: "name",
        key: "name",
      },
      {
        title: "Gender",
        dataIndex: "gender",
        key: "gender",
      },
    ],
    pagination,
  };

  return ;
};

export default UserList;

针对这个问题,我自定义了一个hook,将公共逻辑抽出来:

import { Table, Button } from "antd";
import { mock, Random } from "mockjs";
import React from "react";
import useTable from "../hooks/useTable";

const fetchUsers = (pageIndex, pageSize) => {
  return Promise.resolve(
    mock({
      "total|10-100": pageSize * 5.5,
      "list|10": [
        {
          "name|1": [
            Random.name(),
            Random.name(),
            Random.name(),
            Random.name(),
          ],
          "gender|1": ["male", "female"],
        },
      ],
    })
  );
};

const columns = [
  {
    title: "Name",
    dataIndex: "name",
    key: "name",
  },
  {
    title: "Gender",
    dataIndex: "gender",
    key: "gender",
  },
];

const UserListWithHook = () => {
  const { tableProps, query } = useTable(fetchUsers);

  const handleRefresh = () => {
    query();
  };

  return (
    
); }; export default UserListWithHook;
import { useEffect, useState } from "react";
import useAsync from "./useAsync";

const useTable = (fetchDataSource = () => Promise.resolve([])) => {
  const [params, setParams] = useState({
    pageSize: 10,
    pageIndex: 1,
  });

  const {
    res = {},
    isLoading,
    query,
  } = useAsync((originParams = {}) =>
    fetchDataSource({ ...params, ...originParams })
  );

  useEffect(() => {
    query(params);
  }, [params]);

  const pagination = {
    current: params.pageIndex,
    pageSize: params.pageSize,
    onChange: (index, pageSize) => {
      setParams({
        ...params,
        pageIndex: index,
        pageSize: pageSize || params.pageSize,
      });
    },
  };

  const tableProps = {
    dataSource: res.list,
    pagination,
    loading: isLoading,
  };

  return {
    tableProps,
    query,
    params,
  };
};

export default useTable;

用上自定义Hook useTable之后,UserList组件就清爽多了。
在usetTable中,还嵌套使用了另一个自定义hook,也就是useAsync,关于这个自定义组件的详细内容见https://www.jianshu.com/p/7b6f3aaa1a27?v=1667120684038

你可能感兴趣的:([Hook]useTable)