en-US

This example shows how to load data remotely.

zh-CN

该示例展示了如何实现远程加载数据。

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

import { useImmer, useAsync } from '@react-devui/hooks';
import { DTable, DButton, DSeparator, DSpinner, DPagination } from '@react-devui/ui';

const remoteData = Array.from({ length: 100 }).map((_, i) => ({
  name: `Name ${i + 1}`,
  age: `${i % 30}`,
  address: `Room 100${i}, Building 2, Fandou Garden, Fandou Street`,
}));
const filterList = {
  name: Array.from({ length: 6 }).map((_, i) => ({ label: `Name ${i + 1}`, value: `Name ${i + 1}` })),
};
export default function Demo() {
  const dataRef = useRef({});
  const async = useAsync();

  const [list, setList] = useState([]);
  const [loading, setLoading] = useState(true);
  const [page, setPage] = useState(1);
  const [pageSize, setPageSize] = useState(10);
  const [total, setTotal] = useState(0);

  const [sort, setSort] = useImmer({});
  const [filter, setFilter] = useImmer({ name: null });

  const fetchData = (request: { sort?: 'age' | '-age'; 'filter[name:eq]'?: string; page: number; pageSize: number }) => {
    setLoading(true);

    request = Object.assign(
      {
        sort: sort.age === 'ascend' ? 'age' : sort.age === 'descend' ? '-age' : undefined,
        'filter[name:eq]': filter.name ? filter.name : undefined,
        page,
        pageSize,
      },
      request
    );

    dataRef.current.clearTid?.();
    dataRef.current.clearTid = async.setTimeout(() => {
      setLoading(false);

      const response = (() => {
        const sortFn = (() => {
          if (request.sort) {
            return (a, b) => (Number(a.age) - Number(b.age)) * (request.sort === 'age' ? 1 : -1);
          }
        })();
        const filterFn = (data) => {
          if (request['filter[name:eq]'] && data.name !== request['filter[name:eq]']) {
            return false;
          }
          return true;
        };
        const list = remoteData.filter(filterFn);
        if (sortFn) {
          list.sort(sortFn);
        }
        const meta = {
          page:
            (request.page - 1) * request.pageSize >= list.length ? Math.max(Math.ceil(list.length / request.pageSize), 1) : request.page,
          total: list.length,
        };
        const data = list.slice((meta.page - 1) * request.pageSize, meta.page * request.pageSize);
        return { meta, data };
      })();

      setList(response.data);
      setPage(response.meta.page);
      setTotal(response.meta.total);
    }, 1000);
  };

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

  return (
    <DTable>
      <DSpinner dVisible={loading}></DSpinner>
      <table>
        <thead>
          <tr>
            <DTable.Th
              dActions={[
                <DTable.Filter
                  dList={filterList.name}
                  dSelected={filter.name}
                  onSelectedChange={(val) => {
                    setFilter((draft) => {
                      draft.name = val;
                    });
                    fetchData({ 'filter[name:eq]': val ? val : undefined });
                  }}
                />,
              ]}
            >
              Name
            </DTable.Th>
            <DTable.Th
              dSort={{
                active: sort.age ?? null,
                onSort: (order) => {
                  setSort({ age: order });
                  fetchData({ sort: order === 'ascend' ? 'age' : order === 'descend' ? '-age' : undefined });
                },
              }}
            >
              Age
            </DTable.Th>
            <DTable.Th>Address</DTable.Th>
            <DTable.Th>Action</DTable.Th>
          </tr>
        </thead>
        <tbody>
          {list.length === 0 ? (
            <DTable.Empty />
          ) : (
            list.map((data) => (
              <tr key={data.name}>
                <DTable.Td>{data.name}</DTable.Td>
                <DTable.Td>{data.age}</DTable.Td>
                <DTable.Td>{data.address}</DTable.Td>
                <DTable.Td dNowrap>
                  <DButton dType="link">Edit</DButton>
                  <DSeparator dVertical></DSeparator>
                  <DButton dType="link">Delete</DButton>
                </DTable.Td>
              </tr>
            ))
          )}
        </tbody>
      </table>
      <DPagination
        dActive={page}
        dTotal={total}
        dPageSize={pageSize}
        dCompose={['pages', 'page-size']}
        onPaginationChange={(page, pageSize) => {
          setPage(page);
          setPageSize(pageSize);
          fetchData({ page, pageSize });
        }}
      ></DPagination>
    </DTable>
  );
}