@aligov/components-use-form-table-hooks

搭配基于fusion封装的GovTable使用。

tnpm i @aligov/components-use-form-table-hooks -S

基础用法

下面是场景的列表查询的例子,由 form + table + 分页组成

import React from 'react';
import { Pagination } from '@alifd/next';
import { Field, FormButtonGroup, Reset, SchemaForm, Submit } from '@uform/next';
import GovTable from '@aligov/components-gov-table';
import useFormTableHooks from '@aligov/components-use-form-table-hooks';

async function getData(params) {
  return await {
    total: 1000,
    list: [
      {id: 1, content: 'a'},
      {id: 2, content: 'b'}
    ]
  };
}

function Page() {
  const {
    loading, // 是否为加载状态
    data = {}, // 当前列表数据
    search,  // 表单搜索触发提交
    reload,  // 重新搜索,用于操作后更新列表场景
    changeTable, // 表格翻页接口
  } = useFormTableHooks(getData);

  const columns = [
    {
      title: 'ID',
      dataIndex: 'id',
    },
    {
      title: 'Content',
      dataIndex: 'content'
    }
  ];

  const { list, total = 0, current = 1, pageSize = 10 } = data;

  return (
    <div>
      <SchemaForm
        labelCol={6}
        wrapperCol={18}
        autoAddColon={false}
        onSubmit={search}
      >
        <Field name="id" type="string"/>

        <FormButtonGroup>
          <Submit>查询</Submit>
          <Reset>重置</Reset>
        </FormButtonGroup>
      </SchemaForm>

      <GovTable loading={loading} dataSource={list} columns={columns} hasBorder={false} />

      <Pagination
        onChange={changeTable}
        current={current}
        total={total}
        pageSize={pageSize}
      />
    </div>
  );
}

API

const hookExport = useFormTableHooks(searchService, options);

参数

参数 说明 类型 默认值
searchService 必须,根据表单及分页参数来查询列表内容 (any) => Promise
options 可选,定制处理 Object {}
options.defaultPageSize 表格每页条目数量 Number 10
options.initData 用来给表单或其它查询相关参数设定默认值 Object {}
options.waitUntilManualCall 初始化后不自动查询,配合 hook 返回结果中的 readyToSearch 方法来使用,用于需要等待某些异步结果才能查询的场景 Boolean false
options.trim 是否在发送请求时,对请求参数中字符串类型的值做 trim 处理(仅第一层) Boolean true
options.initSort 初始化的表格排序设置,详见 Fusion 中 Table 的 sort 属性 Object {}
options.sortFormatter 排序参数发送请求前的格式化方案,默认是把所有对象放到 sortParams key 中 (any) => any sortParams => ({ sortParams: sortParams })
options.initFilterParams 初始化时的表格过滤设置,详见 Fusion 中 Table 的 filterParams 属性 Object {}
options.filterFormatter 表格过滤参数发送请求前的格式化方案,默认是把所有对象放到 filterParams key 中 (any) => any filterParams => ({ filterParams: filterParams })

返回结果

返回结果是一个对象,包含以下属性

属性 说明 类型
loading 是否正在请求中 Boolean
formData form 表单参数,包含了 options.initData中的内容 Object
data 列表数据,主要是 searchService 的返回结果 any
search 触发表单查询,会重置页码为 1。可携带额外的参数来查询 (extraParams?: object} => void
reload 刷新当前页,常用于表格操作后刷新的场景,可携带额外的参数来表示可能移除的数量,用于避免最后一页条目都不再展示后页码不对的场景 (deleteCount: Number = 0) => void
changeTable 表格翻页,主要用于 Fusion Pagination 组件的 onChange 属性 (current: number) => void
readyToSearch 调用后解除 options.waitUntilManualCall 的控制,触发表单查询及后续的响应 Function
updateFormData 更新表单数据,但不触发查询,不常用 (data: Object) => void
updateTableData 直接更新列表数据,主要用于操作后不发送请求来完全刷新列表的场景,不常用 (tableData: any) => void
updateTableRow 直接更新列表某行数据,不常用 (index: number, rowData: any) => void
sortParams Table 的 sort 属性 Object
onSort Table 的 onSort 属性 (dataIndex: string, order: string) => void
filterParams Table 的 filterParams 属性 Object
onFilter Table 的 onFilter 属性 (filterParams: Object) => void

相关信息

初始化时不马上发请求

默认情况下,在调用 hooks 时就会马上调用 searchService 来获取数据。但如果需要先获取某些异步数据(如表单某些地方需要通过异步来获取并设置默认值),那么可通过 options.waitUntilManualCall 以及返回的 readyToSearch 来搭配使用。

例子:

const { readyToSearch, updateFormData } = useFormTableHooks(searchService, { waitUntilManualCall: true });

asyncFn().then((res = {}) => {
    updateFormData(res);
    readyToSearch();
});

请求和分页

searchService 一般应该满足前后端接口规范中的[列表类接口][guide-ajax-list]的约定里的 data 格式(注意:后端接口本身应满足完全的结构,但经通用请求库包装后,service 只会返回接口里的有效数据 data), 即假设是分页的场景。

但如果接口本身不满足通用的列表查询规范,而是直接返回一个数组。那么 hook 返回结果种的 data 将不是一个 object,而是数组。这个时候则需要根据实际的数据结构来展示。

DEMO 列表

简单用法

import React, {Component} from 'react';
import ReactDOM from 'react-dom';
import {Button, Message, Pagination} from '@alifd/next';
import {Field, FormButtonGroup, FormItemGrid, Reset, SchemaForm, Submit} from '@uform/next';
import UseFormTableHooks, {ISearchParams} from '@aligov/components-use-form-table-hooks';
import GovTable from '@aligov/components-gov-table';

const dataSource = {
  total: 55,
  list: [
    {
      name: '张三',
      age: '12'
    }, {
      name: '李四',
      age: '13'
    }]
};

const getData = (params) => {
  console.log('查询参数', params);
  return new Promise((resolve, reject) => {
    setTimeout(() => resolve(dataSource), 1000);
  })
};

function App() {
  const {
    loading,
    data = {},
    formData = {},
    search,
    reload,
    changeTable,
    updateFormData,
  } = UseFormTableHooks(getData, {
    initData: {},
  });

  const {list, total, current, pageSize} = data;

  const columns = [{
    title: '姓名',
    dataIndex: 'name'
  }, {
    title: '年龄',
    dataIndex: 'age'
  }];

  return (
    <div>
      <SchemaForm
        labelCol={6}
        wrapperCol={18}
        value={formData}
        onChange={updateFormData}
        onSubmit={search}
      >
        <FormItemGrid cols={[8, 8, 8]}>
          <Field name="name" type="string" title="姓名"></Field>
          <Field name="age" type="string" title="年龄"/>
        </FormItemGrid>
        <FormButtonGroup>
          <Submit>查询</Submit><Reset>重置</Reset></FormButtonGroup>
      </SchemaForm>

      <GovTable loading={loading} hasBorder={false} dataSource={list} columns={columns}/>

      <Pagination
        onChange={changeTable}
        current={current}
        total={total}
        pageSize={pageSize}
        className={'pagination'}
      />
    </div>
  );
}

ReactDOM.render((
  <App/>
), mountNode);

操作后 reload 表格

import React, {Component} from 'react';
import ReactDOM from 'react-dom';
import {Button, Message, Pagination} from '@alifd/next';
import {Field, FormButtonGroup, FormItemGrid, Reset, SchemaForm, Submit} from '@uform/next';
import UseFormTableHooks, {ISearchParams} from '@aligov/components-use-form-table-hooks';
import GovTable from '@aligov/components-gov-table';

const dataSource = {
  list: [],

  init() {
    for (let i = 0; i < 55; i++) {
      this.list.push({
        name: `name-${i}`,
        age: Math.round(Math.random() * 50)
      });
    }
  },

  getPageData(current, pageSize) {
    const start = (current - 1) * pageSize;
    const end = start + pageSize;
    const list = this.list.slice(start, end);

    return {
        current,
        pageSize,
        total: this.list.length,
        list,
    }
  },

  remove(count) {
    this.list = this.list.slice(0, this.list.length - count);
  },

  reset() {
    this.list = [];
    this.init();
  }
};
dataSource.init();

const getData = (params) => {
  console.log('查询参数', params);
  return new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve(dataSource.getPageData(params.current, params.pageSize));
    }, Math.round(Math.random()*1000));
  })
};

function App() {
  const {
    loading,
    data = {},
    formData = {},
    search,
    reload,
    changeTable,
    updateFormData,
    updateTableData,
    updateTableRow,
  } = UseFormTableHooks(getData, {
    initData: {},
  });

  const {list, total, current, pageSize} = data;

  const columns = [{
    title: '姓名',
    dataIndex: 'name'
  }, {
    title: '年龄',
    dataIndex: 'age'
  }];

  const handleDelete1Row = () => {
    dataSource.remove(1);
    reload(1);
  };

  const handleReset = () => {
    dataSource.reset();
    reload();
  };

  return (
    <div>
      <SchemaForm
        labelCol={6}
        wrapperCol={18}
        value={formData}
        onChange={updateFormData}
        onSubmit={search}
      >
        <FormItemGrid cols={[8, 8, 8]}>
          <Field name="name" type="string" title="姓名" />
          <Field name="age" type="string" title="年龄"/>
        </FormItemGrid>
        <FormButtonGroup>
          <Submit>查询</Submit><Reset>重置</Reset></FormButtonGroup>
      </SchemaForm>

      <div style={{ margin: '20px 0' }}>
        <Button onClick={handleReset}>重置数据</Button>
        <Button onClick={handleDelete1Row} style={{ marginLeft: 20 }}>删除一行</Button>
        <Button onClick={reload} style={{ marginLeft: 20 }}>不减少数据的操作</Button>
      </div>

      <GovTable loading={loading} hasBorder={false} dataSource={list} columns={columns}/>

      <Pagination
        onChange={changeTable}
        current={current}
        total={total}
        pageSize={pageSize}
        className={'pagination'}
      />
    </div>
  );
}

ReactDOM.render((
  <App/>
), mountNode);

直接更新表格数据

import React, {Component} from 'react';
import ReactDOM from 'react-dom';
import {Button, Message, Pagination} from '@alifd/next';
import {Field, FormButtonGroup, FormItemGrid, Reset, SchemaForm, Submit} from '@uform/next';
import UseFormTableHooks, {ISearchParams} from '@aligov/components-use-form-table-hooks';
import GovTable from '@aligov/components-gov-table';

const dataSource = {
  current: 1,
  total: 20,
  pageSize: 15,
  list: [
    {name: '张三', age: '12'},
    {name: '李四', age: '13'}
  ]
};

const getData = (params) => {
  console.log('查询参数', params);
  return new Promise((resolve, reject) => {
    resolve(dataSource);
  })
};

function App() {
  const {
    loading,
    data = {},
    formData = {},
    search,
    reload,
    changeTable,
    updateFormData,
    updateTableData,
    updateTableRow,
  } = UseFormTableHooks(getData, {
    initData: {},
  });

  const {list, total, current, pageSize} = data;

  const columns = [{
    title: '姓名',
    dataIndex: 'name'
  }, {
    title: '年龄',
    dataIndex: 'age'
  }];

  const handleUpdateTableData = () => {
    const newList = [
      {name: '刘一', age: '22'},
      {name: '陈二', age: '33'}
    ];
    updateTableData({
      ...data,
      list: newList
    });
  };

  const handleUpdateFirstRow = () => {
    const newFirstRow = {name: '黄药师', age: '40'};
    updateTableRow(0, newFirstRow);
  };

  return (
    <div>
      <SchemaForm
        labelCol={6}
        wrapperCol={18}
        value={formData}
        onChange={updateFormData}
        onSubmit={search}
      >
        <FormItemGrid cols={[8, 8, 8]}>
          <Field name="name" type="string" title="姓名"></Field>
          <Field name="age" type="string" title="年龄"/>
        </FormItemGrid>
        <FormButtonGroup>
          <Submit>查询</Submit><Reset>重置</Reset></FormButtonGroup>
      </SchemaForm>

      <div style={{ margin: '20px 0' }}>
        <Button onClick={handleUpdateTableData}>更新表格数据</Button>
        <Button onClick={handleUpdateFirstRow} style={{ marginLeft: 20 }}>更新第一行数据</Button>
      </div>

      <GovTable loading={loading} hasBorder={false} dataSource={list} columns={columns}/>

      <Pagination
        onChange={changeTable}
        current={current}
        total={total}
        pageSize={pageSize}
        className={'pagination'}
      />
    </div>
  );
}

ReactDOM.render((
  <App/>
), mountNode);

排序与过滤

import React, {Component} from 'react';
import ReactDOM from 'react-dom';
import {Button, Message, Pagination} from '@alifd/next';
import {Field, FormButtonGroup, FormItemGrid, Reset, SchemaForm, Submit} from '@uform/next';
import UseFormTableHooks, {ISearchParams} from '@aligov/components-use-form-table-hooks';
import GovTable from '@aligov/components-gov-table';

const dataSource = {
  total: 55,
  list: [
    {
      name: '张三',
      age: '12'
    }, {
      name: '李四',
      age: '13'
    }]
};

const nameFilters = [
    { label: '张三', value: '张三' },
    { label: '李四', value: '李四' },
]

const getData = (params) => {
  console.log('查询参数', params);
  return new Promise((resolve, reject) => {
    setTimeout(() => resolve(dataSource), 1000);
  })
};

function App() {
  const {
    loading,
    data = {},
    formData = {},
    search,
    reload,
    changeTable,
    updateFormData,
    sortParams,
    onSort,
    filterParams,
    onFilter,
  } = UseFormTableHooks(getData, {
    initData: {},
  });

  const {list, total, current, pageSize} = data;

  const columns = [{
    title: '姓名',
    dataIndex: 'name',
    filters: nameFilters,
  }, {
    title: '年龄',
    dataIndex: 'age',
    sortable: true,
  }];

  return (
    <div>
      <div>DEMO 中不对数据做实际的排序和过滤,打开 console 看查询参数</div>
      <SchemaForm
        labelCol={6}
        wrapperCol={18}
        value={formData}
        onChange={updateFormData}
        onSubmit={search}
      >
        <FormItemGrid cols={[8, 8, 8]}>
          <Field name="name" type="string" title="姓名" />
          <Field name="age" type="string" title="年龄"/>
        </FormItemGrid>
        <FormButtonGroup>
          <Submit>查询</Submit><Reset>重置</Reset></FormButtonGroup>
      </SchemaForm>

      <GovTable
        loading={loading}
        hasBorder={false}
        dataSource={list}
        columns={columns}
        sort={sortParams}
        onSort={onSort}
        filterParams={filterParams}
        onFilter={onFilter}
      />

      <Pagination
        onChange={changeTable}
        current={current}
        total={total}
        pageSize={pageSize}
        className={'pagination'}
      />
    </div>
  );
}

ReactDOM.render((
  <App/>
), mountNode);