javascript - 如何使用 react-table 实现服务器端分页?

标签 javascript reactjs async-await react-hooks react-table

我是 react 表的新手。我正在尝试实现服务器端分页,但我没有得到关于如何检测新 react 表版本中页面更改的逻辑。我正在使用正确的获取数据我无法检测到更改。每次单击“下一步”按钮时,我应该能够以 20 为增量更改 API 端点中的偏移值以获取新数据。我无法执行此操作。请帮忙。

import React, { useEffect, useState, useMemo } from 'react'
import { URLs } from "../../../Config/url";
import cookie from 'react-cookies';
import "./OrderManagementScreen.css"
import { useTable, usePagination, useSortBy } from 'react-table';
import styled from 'styled-components';


const Styles = styled.div`
padding: 1rem;

table {
  border-spacing: 0;
  border: 1px solid lightgray;
  width: 100%;
  text-align: "center" !important;

  tr {
    :last-child {
      td {
        border-bottom: 0;
        text-align: "center" !important;
      }
    }
  }
  th {
    padding: 3px;
    box-shadow: 0px 5px 7px 2px lightgrey;
  }
  td {
    padding: 5px;
  }
  th,
  td {
    margin: 0;
    text-align: "center";
    border-bottom: 1px solid #73737361;
    border-right: 1px solid #73737361;

    :last-child {
      border-right: 0;
    }
  }
}
.pagination {
}
`;

const WrapperTable = styled.div`
background: #ffffff;
box-shadow: 3px 3px 2px 0px rgb(162 161 161 / 75%) !important;
border-radius: 5px;
`


const Table = ({ columns, data }) => {
  // Use the state and functions returned from useTable to build your UI
  const {
    getTableProps,
    getTableBodyProps,
    headerGroups,
    rows,
    prepareRow,

    page, // Instead of using 'rows', we'll use page,
    // which has only the rows for the active page

    // The rest of these things are super handy, too ;)
    canPreviousPage,
    canNextPage,
    pageOptions,
    pageCount,
    gotoPage,
    nextPage,
    previousPage,
    setPageSize,
    state: { pageIndex, pageSize, sortBy },
  } = useTable(
    {
      columns,
      data,
      initialState: { pageIndex: 0 },
    },
    useSortBy,
    usePagination
  );
  // const sorted = column.isSorted ? (column.isSortedDesc ? " 🔽" : " 🔼") : "";
  // const sorted = column.isSorted ? (column.isSortedDesc ? {borderTop:"1px solid "} :{borderTop:"1px solid "}) : "";
  // Render the UI for your table
  return (
    <>
      <table {...getTableProps()}>
        <thead>
          {headerGroups.map((headerGroup) => (
            <tr {...headerGroup.getHeaderGroupProps()}>
              {headerGroup.headers.map((column) => (
                <th {...column.getHeaderProps(column.getSortByToggleProps())}>
                  {column.render("Header")}
                  {/* Add a sort direction indicator */}
                  <span>
                    {column.isSorted
                      ? column.isSortedDesc
                        ? " 🔽"
                        : " 🔼"
                      : ""}
                  </span>
                </th>
              ))}
            </tr>
          ))}
        </thead>
        <tbody {...getTableBodyProps()}>
          {page.map((row, i) => {
            prepareRow(row);
            return (
              <tr {...row.getRowProps()}>
                {row.cells.map((cell) => {
                  return (
                    <td {...cell.getCellProps()}>{cell.render("Cell")}</td>
                  );
                })}
              </tr>
            );
          })}
        </tbody>
      </table>
      {/* 
      Pagination can be built however you'd like. 
      This is just a very basic UI implementation:
      */}
      <div className="pagination">
        {/* <button
          className="pagination-btn"
          onClick={() => gotoPage(0)}
          disabled={!canPreviousPage}
        >
          First
        </button> */}
        <button
          className="pagination-btn"
          onClick={() => previousPage()}
          disabled={!canPreviousPage}
        >
          Previous
        </button>
        <span className="pagination-btn text-center">
          Page{" "}
          <strong>
            {pageIndex + 1} of {pageOptions.length}
          </strong>{" "}
        </span>
        <button
          className="pagination-btn"
          onClick={() => nextPage()}
          disabled={!canNextPage}
        >
          Next
        </button>
        {/* <button
        className="pagination-btn"
          onClick={() => gotoPage(pageCount - 1)}
          disabled={!canNextPage}
        >
          Last
        </button> */}

        {/* <span>
          | Go to page:{' '}
          <input
            type="number"
            defaultValue={pageIndex + 1}
            onChange={e => {
              const page = e.target.value ? Number(e.target.value) - 1 : 0
              gotoPage(page)
            }}
            style={{ width: '100px' }}
          />
        </span> */}
        {/* <select
          value={pageSize}
          onChange={e => {
            setPageSize(Number(e.target.value))
          }}
        >
          {[10, 20, 30, 40, 50].map(pageSize => (
            <option key={pageSize} value={pageSize}>
              Show {pageSize}
            </option>
          ))}
        </select> */}
      </div>
    </>
  );
};

const OrderManagementScreen = () => {
  const token = cookie.load("userObj").data.token;
  //orderid, outletname, area, distributor, ordervalue, outlet type, discount group, salesofficer,order
  const [tableData, SetData] = useState([]);
  const [loading, setLoading] = React.useState(false);
  const fetchIdRef = React.useRef(0);
  const sortIdRef = React.useRef(0);

  const columns = React.useMemo(
    () => [
      {
        Header: "Order Id",
        accessor: "id",
      },
      {
        Header: "Outlet Name",
        id: "outlet_detail",
        accessor: data => {
          let output = [];
          data.outlet_detail.map(item => {
            return output.push(item.name);
          });
          return output.join(', ');
        }
      },
      {
        Header: "Area",
        id: "area",
        accessor: data => {
          let output = [];
          data.outlet_detail.map(item => {
            return output.push(item.area__name);
          });
          return output.join(', ');
        }
      },
      {
        Header: "Distributor",
        id: "distributor",
        accessor: data => {
          let output = [];
          data.outlet_detail.map(item => {
            return output.push(item.distributor_name);
          });
          return output.join(', ');
        }
      },
      {
        Header: "Order Value",
        accessor: "total_price",
      },
      {
        Header: "Outlet Type",
        id: "outlet_type__name",
        accessor: data => {
          let output = [];
          data.outlet_detail.map(item => {
            return output.push(item.final_value);
          });
          return output.join(', ');
        }
      },
      {
        Header: "Discount Group",
        id: "discount__name",
        accessor: data => {
          let output = [];
          data.outlet_detail.map(item => {
            return output.push(item.discount__name);
          });
          return output.join(', ');
        }
      },
      {
        Header: "Sales Officer",
        id: "sales_officer",
        accessor: data => {
          let output = [];
          data.outlet_detail.map(item => {
            return output.push(item.by_user__username);
          });
          return output.join(', ');
        }
      }
    ],
    []
  );
  const listdata = async () => {
    const response = await fetch(`${URLs.orderUrl}?limit=20&offset=0`, {
      headers: {
        'Content-Type': 'application/json',
        'Authorization': `Token ${token}`
      }
    })

    const data = await response.json();
    SetData(data);
  }


  const fetchData = React.useCallback(({ pageSize, pageIndex, sortBy }) => {
    // This will get called when the table needs new data
    // You could fetch your data from literally anywhere,
    // even a server. But for this example, we'll just fake it.

    // Give this fetch an ID
  console.log(pageIndex);
    console.log(pageSize);
    const fetchId = ++fetchIdRef.current;

    // Set the loading state
    setLoading(true);

    // We'll even set a delay to simulate a server here
    setTimeout(() => {
      // Only update the data if this is the latest fetch
      if (fetchId === fetchIdRef.current) {
        const startRow = pageSize * pageIndex;
        
        const endRow = startRow + pageSize;
        if (sortBy.length === 0) {
          SetData(tableData.sort().slice(startRow, endRow));
        } else {
          SetData(
            tableData
              .sort((a, b) => {
                const field = sortBy[0].id;
                const desc = sortBy[0].desc;
                if (a[field] < b[field]) {
                  return desc ? -1 : 1;
                }
                if (a[field] > b[field]) {
                  return desc ? 1 : -1;
                }
                return 0;
              })
              .slice(startRow, endRow)
          );
        }

        // Your server could send back total page count.
        // For now we'll just fake it, too
        // setPageCount(Math.ceil(serverData.length / pageSize));

        setLoading(false);
      }
    }, 1000);
  }, []);

  useEffect(() => {
    listdata();
  }, [])
  return (
    <div className="p-3 text-center">
      <h4>Order Management</h4>
      <WrapperTable>
        <Styles>
          <Table columns={columns} fetchData={fetchData} data={tableData} />
        </Styles>
      </WrapperTable>
    </div>
  )
}

export default OrderManagementScreen;
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>

最佳答案

首先,您需要了解客户端分页和服务器端分页之间的基本区别。
在客户端分页中,我们已经拥有需要在表格中显示的所有页面的所有数据,这意味着我们也知道总计数(totalcount=pagesize*number of pages)。
现在将其与服务器端分页进行比较。如果我们将页面大小保持为 10 并且我们的服务器上有 100 个数据,但由于我们请求了 10 个,所以我们将只获得 10 个项目,我们将获得我们请求的数据片段。那么分页组件如何知道他需要显示的总页数是多少?
这就是为什么我们在获取数据时也需要服务器的总计数。
但是等等,我们每次都需要它吗?好吧,这取决于您的用例。一般来说,我们第一次需要总计数,或者在我们进行任何查找或过滤的情况下。

现在来到你的解决方案 -
在 react-table 中,如果我们没有明确设置标志 manualPaginationtrue然后它将根据您提供的数据和页面大小处理页数,以便自动处理分页。所以我们需要做这个manualPaginationtrueoptions我们传递给 useTable我们还需要提供 pageCount 的总页数.所以这将是类似的

useTable(
    {
      columns,
      data,
      initialState: { pageIndex: 0 },
    },
    useSortBy,
    usePagination,
    manualPagination: true,
    pageCount: (totalcount/pagesize),//you can handle this calculation in your fetchdata method
  );
然后在新的 useEffect 中添加您的 fecthdata 调用,其中包含您的 pageindex 和
页面大小作为依赖项
React.useEffect(() => {
    fetchData({ pageIndex, pageSize })
  }, [fetchData, pageIndex, pageSize])
我希望这能解决你的问题。这在 react 表 documentation 中也得到了很好的解释。带有适当的代码共享示例。 Check here

关于javascript - 如何使用 react-table 实现服务器端分页?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65227823/

相关文章:

python - 如何在Python中使用asyncio.wait_for到run_until_complete同步调用异步方法

javascript - jquery 每 50 秒显示一个警报,如何?

reactjs - 如何使用 Typescript 创建 React 多态组件?

node.js - 每次安装软件包时都必须重新安装 node_modules

javascript - react 堆栈导航

javascript - 尝试将 promisified 函数重构为 try-catch block

c# - 在 Xamarin Forms 中的 PCL 同步方法中调用异步函数

javascript - 为什么我的 2 对象深度比较失败了?

javascript - 'li' 鼠标悬停事件被子 'a' 元素显示 block 阻止

javascript - while循环抛出错误javascript