如何使用 Nextjs、Prisma 和 SWR 创建分页表?

del*_*esb 1 javascript reactjs next.js prisma swr

我正在尝试使用 Nextjs、Prisma 和 SWR 创建一个分页表。该表将显示按 ID 排序的发票列表。这是它的外观示例:

分页表

我使用Prisma将所有数据获取到 api 路由,并使用 SWR在 UI 上显示数据并重新验证。这是迄今为止的 UI 代码:

            {InvoiceData.map((invoice, key) => {
              return (
                <tr key={key}>
                  <td className="font-medium">
                    #
                    {invoice.nro_factura &&
                      Number(invoice.nro_factura).toString()}
                  </td>
                  <td className="whitespace-pre-wrap">
                    {invoice.fecha_emision &&
                      moment(invoice.fecha_emision).format("MMM DD, YYYY")}
                  </td>
                  <td className="font-medium">
                    ${invoice.total && Number(invoice.total).toLocaleString()}
                  </td>
                  <td>
                    <Badge
                      status={
                        invoice.total === invoice.pagos
                          ? 0
                          : invoice.anulada
                          ? 2
                          : 1
                      }
                      title={
                        invoice.total === invoice.pagos
                          ? "Pagado"
                          : invoice.anulada
                          ? "Borrada"
                          : "Pendiente"
                      }
                    />
                  </td>
                  <td className="customer-column">
                    {CustomersData.map((customer) => {
                      if (customer.cliente_id === invoice.cliente_id) {
                        return customer.nombre_clte;
                      }
                      return null;
                    })}
                  </td>
                </tr>
              );
            })}
Run Code Online (Sandbox Code Playgroud)

这是 api 路由内的代码:

import { prisma } from "../../../prisma/index.ts";

export default async function getInvoicesData(req, res) {
  let InvoiceData = await prisma.factura.findMany({
    orderBy: {
      nro_factura: "desc",
    },
  });
  return res.status(200).json(InvoiceData);
}
Run Code Online (Sandbox Code Playgroud)

NG2*_*235 14

分页有两种类型:偏移分页和光标分页。偏移分页的工作原理是跳过一定数量后获取行。游标分页的工作原理是对行进行排序,然后获取游标属性(即 ID)大于传递的游标值(即前端最后一行的 ID)的行。

抵消

图片来自 Prisma 文档 来源:Prisma 文档

需要将查询参数发送到 API 路由,例如page。该参数可以代表表格底部的页码。将该负 1 ( page - 1) 乘以每页的结果数 ( (page - 1) * size)。通过 Prisma 将其作为 发送到数据库skip。这将跳过表的前 X 行。您还必须包含该take参数,否则您将提取表的所有结果,不包括 之前的行skip

一个例子:

const results = await prisma.post.findMany({
  skip: 10, // How many rows to skip
  take: 10, // Page size
})
Run Code Online (Sandbox Code Playgroud)

然后,您的 API 查询可能如下所示:https://example.com/api/invoices?page=2。如果页面大小为10,则页面2将包含“number”行11-20(跳过(2 - 1) * 10 = 10( (page - 1) * size))。

然而,当行数很多时,他的速度可能会变慢。另一种方法是光标分页(见下文)

光标

光标分页 来源:Prisma 文档

这将需要按 ID 排序的查询。您仍然需要获取一定数量的行(即 10 行),并将最后一项的 ID 作为游标传递(对于第 2 页及以上页面):

const firstQueryResults = await prisma.post.findMany({
  take: 10, // Page size
  skip: 1, // Skip the cursor row
  cursor: {
    id: myCursor, // The cursor - only on pages 2 and above
  },
  orderBy: {
    id: 'asc', // Ordering results
  },
})
Run Code Online (Sandbox Code Playgroud)

这将获取 ID 大于光标的所有行(即myCursor

使用 API 请求中的查询参数cursor来设置光标。

光标分页速度要快得多,但是需要排序。也可以按时间戳排序。然后,您只需要按查询中的时间戳进行排序。

前端

然后,您可以在前端使用 API 响应中的数据更新存储结果的变量。我建议您在 API 响应中包含一个包含行数的属性(count来自 Prisma),以便您可以除以页码并在表格底部显示正确的按钮数量。

对于偏移分页,单击按钮时,将页码作为查询参数发送到 API。

对于光标分页,简单地使用下一个和后退按钮会更容易。对于下一个按钮,通过发送光标来分页。对于返回,取负数行(即-10) - 这可以通过设置另一个查询参数来完成,例如direction(您将需要实现此逻辑)。可以有页码;您需要做的就是使用页面之间的行数差异cursorskip(例如,从第2页转到第5页会跳过第3页。因此,您需要使用第2页上最后一项的光标,并跳过第3页和第4页的结果数(即20))

根据 SWR 文档,您可以创建一个传递给页面的 API 查询的变量。可以将其修改为光标和方向。

function App () {
  const [pageIndex, setPageIndex] = useState(0);

  // The API URL includes the page index, which is a React state.
  const { data } = useSWR(`/api/data?page=${pageIndex}`, fetcher);

  // ... handle loading and error states

  return <div>
    {data.map(item => <div key={item.id}>{item.name}</div>)}
    <button onClick={() => setPageIndex(pageIndex - 1)}>Previous</button>
    <button onClick={() => setPageIndex(pageIndex + 1)}>Next</button>
  </div>
}
Run Code Online (Sandbox Code Playgroud)

额外的改进

您可以通过将其作为查询参数发送来动态设置限制或页面大小