TanStack / table

🤖 Headless UI for building powerful tables & datagrids for TS/JS - React-Table, Vue-Table, Solid-Table, Svelte-Table
https://tanstack.com/table
MIT License
25.1k stars 3.07k forks source link

Failed to monitor data changes, resulting in page turning without re-rendering. #5695

Closed pk111and222 closed 2 months ago

pk111and222 commented 2 months ago

TanStack Table version

8.20.1

Framework/Library version

"next": "14.1.0","react": "^18"

Describe the bug and the steps to reproduce it

"use client"
import React, { useEffect, useState } from "react"

import {
  PaginationState,
  ColumnDef,
  SortingState,
  flexRender,
  getCoreRowModel,
  ColumnFiltersState,
  getPaginationRowModel,
  getSortedRowModel,
  getFilteredRowModel,
  useReactTable,
} from "@tanstack/react-table"

import {
  Table,
  TableBody,
  TableCell,
  TableHead,
  TableHeader,
  TableRow,
} from "@/components/ui/table"

import { Input } from "@/components/ui/input"
import { DataTablePagination } from "./DataTablePagination"

interface DataTableProps<TData> {
  columns: ColumnDef<TData>[]
  fetch: (page: PaginationState, filter: ColumnFiltersState, sort: SortingState) => Promise<{
    list: TData[],
    total: number
  }>
  onRowSelection?: (selectRow: TData[]) => void
}

export function DataTable<TData>({
  columns,
  fetch,
  onRowSelection
}: DataTableProps<TData>) {
  const skipPageResetRef = React.useRef<boolean>()
  const [data, setData] = useState<TData[]>([])
  const [total, setTotal] = useState<number>(0)
  const [sorting, setSorting] = React.useState<SortingState>([])
  const [columnFilters, setColumnFilters] = React.useState<ColumnFiltersState>([])
  const [rowSelection, setRowSelection] = React.useState({})
  const [pagination, setPagination] = React.useState<PaginationState>({ pageIndex: 0, pageSize: 1 })

  const getData = async () => {
    const res = await fetch(pagination, columnFilters, sorting)
    skipPageResetRef.current = true
    setTotal(res.total)
    setData(res.list)
  }

  useEffect(() => {
    getData()
  }, [sorting, columnFilters, pagination.pageIndex, pagination.pageSize])

  useEffect(() => {
    const l = Object.keys(rowSelection).map((e)=> data[Number(e)])
    onRowSelection && onRowSelection(l)
  }, [rowSelection])

  useEffect(() => {
    skipPageResetRef.current = false
  })

  const table = useReactTable({
    data,
    columns,
    onPaginationChange: setPagination,
    getCoreRowModel: getCoreRowModel(),
    getPaginationRowModel: getPaginationRowModel(),
    onSortingChange: setSorting,
    getSortedRowModel: getSortedRowModel(),
    onColumnFiltersChange: setColumnFilters,
    onRowSelectionChange: setRowSelection,
    getFilteredRowModel: getFilteredRowModel(),
    autoResetPageIndex: !skipPageResetRef.current,
    autoResetExpanded: !skipPageResetRef.current,
    rowCount: total,
    debugTable: true,
    state: {
      pagination,
      sorting,
      columnFilters,
      rowSelection,
    }
  })

  return (
    <div>
       <div className="flex items-center py-4">
        <Input
          placeholder="Filter emails..."
          value={(table.getColumn("email")?.getFilterValue() as string) ?? ""}
          onChange={(event) =>
            table.getColumn("email")?.setFilterValue(event.target.value)
          }
          className="max-w-sm"
        />
      </div>
      <div className="rounded-md border">
        <Table>
          <TableHeader>
            {table.getHeaderGroups().map((headerGroup) => (
              <TableRow key={headerGroup.id}>
                {headerGroup.headers.map((header) => {
                  return (
                    <TableHead key={header.id}>
                      {header.isPlaceholder
                        ? null
                        : flexRender(
                            header.column.columnDef.header,
                            header.getContext()
                          )}
                    </TableHead>
                  )
                })}
              </TableRow>
            ))}
          </TableHeader>
          <TableBody>
            {table.getRowModel().rows?.length ? (
              table.getRowModel().rows.map((row) => (
                <TableRow
                  key={row.id}
                  data-state={row.getIsSelected() && "selected"}
                >
                  {row.getVisibleCells().map((cell) => (
                    <TableCell key={cell.id}>
                      {flexRender(cell.column.columnDef.cell, cell.getContext())}
                    </TableCell>
                  ))}
                </TableRow>
              ))
            ) : (
              <TableRow>
                <TableCell colSpan={columns.length} className="h-24 text-center">
                  No results.
                </TableCell>
              </TableRow>
            )}
          </TableBody>
        </Table>
      </div>
      <DataTablePagination table={table} />
    </div>
  )
}

this demo in the getData perform page turning behavior . list is It was executed and set successfully, but the table was not re-rendered. so ,i dont know why

Your Minimal, Reproducible Example - (Sandbox Highly Recommended)

sorry, i didnt created some data

Screenshots or Videos (Optional)

No response

Do you intend to try to help solve this bug with your own PR?

No, because I do not know how

Terms & Code of Conduct

KevinVandy commented 2 months ago

since data is an array, remember to spread the new data with ... https://react.dev/learn/updating-arrays-in-state

pk111and222 commented 2 months ago

since data is an array, remember to spread the new data with ... https://react.dev/learn/updating-arrays-in-state

I'm sorry, I didn't understand the meaning here. I tried to make some changes and found that the page got stuck when switching.

  const table = useReactTable({
    data: [...data],
    columns,
    onPaginationChange: setPagination,
    getCoreRowModel: getCoreRowModel(),
    getPaginationRowModel: getPaginationRowModel(),
    onSortingChange: setSorting,
    getSortedRowModel: getSortedRowModel(),
    onColumnFiltersChange: setColumnFilters,
    onRowSelectionChange: setRowSelection,
    getFilteredRowModel: getFilteredRowModel(),
    autoResetPageIndex: !skipPageResetRef.current,
    autoResetExpanded: !skipPageResetRef.current,
    rowCount: total,
    debugTable: true,
    state: {
      pagination,
      sorting,
      columnFilters,
      rowSelection,
    }
  })

I can confirm that the props data passed into the component is unchanged.So where does this infinite loop happen?