Tanstack/React-Table infinite loop when access selected row outside of table component

211 Views Asked by At

Hello i am using shadcn table with tanstack table and while trying to access the selected rows outside of Table component i get infinite loop error, is there another way ? except using refs and onRowSelectionChange method

function TableComponent ({columns, data, paginationProps, setSelectedRows}){

const manualPagination = useMemo(() => !!paginationProps, [paginationProps]);
const [rowSelection, setRowSelection] = useState({});
const [pagination, setPagination] = useState({
  pageIndex: 0,
  pageSize: manualPagination ? paginationProps?.rowsPerPage || 0 : data.length,
});

const table = useReactTable({
  data,
  columns: columns,
  pageCount: manualPagination ? paginationProps?.totalPages : undefined,
  manualPagination,
  state: {
    rowSelection,
    pagination,
  },
  getRowId(originalRow: any) {
    return originalRow.id;
  },
  getCoreRowModel: getCoreRowModel(),
  onPaginationChange: (updater) => {
    setPagination(updater);
  },
  onRowSelectionChange: (updater) => {
    setRowSelection(updater);
  },
  getPaginationRowModel: getPaginationRowModel(),
});

const rows = table.getSelectedRowModel().rows;

useEffect(() => {
  console.log('Re Render') // Re-Renders Normal;
}, [rows])

// ! INFINITE LOOP
useEffect(() => {
  console.log('Re Render 2') // I get error of infinite loop
  setSelectedRows?.(rows.map((row) => row.original));
}, [rows]);

}

function ParentComponent (props){
const [selectedRows, setSelectedRows = useState ([])

useEffect(() =>{
  // do your custom handle of the selection
},[selectedRows])

return (
  <Table 
   columns={columns}
   data={data}
   setSelectedRows={setSelectedRows}>
  />
  ......
)
} 

I tried using useRef and onPaginationChange and it works but useref won't detect change and onPaginationChange needs settimeout

1

There are 1 best solutions below

1
On

Problem you face has to do with the shallow comparison in memory of the rows object. When your state is updated, the rows object will have a different location in memory and thus retrigger the effect.

Another approach could be to pass your setState function as a callback to your Table component

export default function Table({
  onRowSelect,
}) {
  const [rowSelection, setRowSelection] = useState<RowSelectionState>({});

  const table = useReactTable({
    state: {
      rowSelection,
    },
    onRowSelectionChange: setRowSelection,
  });

  useEffect(() => {
    if (onRowSelect) {
      const selected = table
        .getSelectedRowModel()
        .rows.map(({ original }) => original);

      onRowSelect(selected);
    }
  }, [onRowSelect, rowSelection, table]);
}

And use it like this by passing the state update function to onRowSelect

const [selected, setSelected] = useState([])

<Table onRowSelect={setSelected} />