table icon indicating copy to clipboard operation
table copied to clipboard

if data is empty array, then rendering table is causing infinite rerenders

Open originalkamaal opened this issue 7 months ago • 1 comments

TanStack Table version

10.7.0

Framework/Library version

19.0.0

Describe the bug and the steps to reproduce it

in below code, data is being fetch through an api, and meanwhile it is being fetched an empty array is passed to useReactTable, and in this case its causing inifinite rerenders and some time freezing the app..

PS: below code is fixed by condtional rendering by checking if data is not empty, try similar code with removing the check or passing empty array..

please handle empty array edge case, i can understand that columns configuration depends on data but this is something developer would face difficulties finding the problem as we know infinite rerending issue is something little difficult to debug

Your Minimal, Reproducible Example - (Sandbox Highly Recommended)

NA

Screenshots or Videos (Optional)

import { useNavigate, useParams } from "react-router-dom"; import { TABS_ASSESSMENTS } from "./constants"; import { useAssessmentData } from "./useAssessmentData"; import { getCoreRowModel, getSortedRowModel, SortingState, useReactTable, } from "@tanstack/react-table"; import { useAssessmentColumns } from "./useAssessmentColumns"; import { useState } from "react"; import { useAssessmentActionColumns } from "./useAssessmentActionColumns"; import { useTypedNavigate, PageHeader, Tabs, TableV2, IPartnerAssessmentCatalogueItem, useAuth, useGetAllPartnersAssessmentActionsQuery, IPartnerAction, Spinner, } from "@regahead/common";

export type AssessmentTabs = | "actions" | "all" | "assigned" | "inProgress" | "completed"; export const PageAssessment = () => { const { org } = useAuth(); const navigate = useNavigate(); const typedNavigate = useTypedNavigate();

const [sorting, setSorting] = useState<SortingState>([]);

const [selectedAssessment, setSelectedAssessment] = useState<number[]>([]); const { data, isLoading: assessmentLoading } = useAssessmentData(); const { activeTab = "all" } = useParams<{ activeTab?: AssessmentTabs; }>();

const columns = useAssessmentColumns( activeTab as Exclude<AssessmentTabs, "actions">, selectedAssessment, data, setSelectedAssessment );

const table = useReactTable<IPartnerAssessmentCatalogueItem>({ data: data[activeTab].data as any[], columns, state: { sorting, }, onSortingChange: setSorting, getCoreRowModel: getCoreRowModel(), getSortedRowModel: getSortedRowModel(), });

const { data: actionData, isLoading } = useGetAllPartnersAssessmentActionsQuery(org!.id); const actionColumns = useAssessmentActionColumns(actionData ?? []); const actiontable = useReactTable<IPartnerAction>({ data: actionData ?? [], columns: actionColumns, state: { sorting, }, onSortingChange: setSorting, getCoreRowModel: getCoreRowModel(), getSortedRowModel: getSortedRowModel(), });

const handleTabNavigation = (tabId: string) => { navigate(/assessments/${tabId as typeof activeTab}); };

if (isLoading || assessmentLoading) { return ( <div className="w-full flex items-center justify-center py-56"> <Spinner /> ); }

return (

<PageHeader title={"Risk Assessment Catalogue"} subtitle={"Find a complete list of all the Risk assessments."} /> <div className="px-6"> <Tabs key="opportunity-tabs" tabs={[ ...TABS_ASSESSMENTS({ actions: data?.actions.count, all: data?.all.count, assigned: data?.assigned.count, inProgress: data?.inProgress.count, completed: data?.completed.count, }), ]} onTabChange={handleTabNavigation} disabled={false} activeTab={activeTab} /> {activeTab === "actions" && ((actionData?.length ?? 0) > 0 ? ( <TableV2 onClickRow={() => {}} table={actiontable} /> ) : ( <div className="flex items-center justify-center py-56"> <p className="text-rega-grey-darker text-sm">No actions found
))} {activeTab !== "actions" && ( <div className="w-full"> {data[activeTab].data.length > 0 ? ( <TableV2 onClickRow={(row) => { typedNavigate<"/assessment/:partnerId/:id">( "/assessment/:partnerId/:id", row, { id: row?.assessmentId, partnerId: org!.id, } ); }} table={table} /> ) : ( <div className="flex items-center justify-center py-56"> <p className="text-rega-grey-darker text-sm">No data found )} )} ); };

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

None

Terms & Code of Conduct

  • [x] I agree to follow this project's Code of Conduct
  • [x] I understand that if my bug cannot be reliable reproduced in a debuggable environment, it will probably not be fixed and this issue may even be closed.

originalkamaal avatar Apr 30 '25 06:04 originalkamaal

Instead of writing this:

function Component() {
  useReactTable({
    data: actionData ?? [],
  })
}

...write this:

const EMPTY_ARRAY = [] as const;

function Component() {
  useReactTable({
    data: actionData ?? EMPTY_ARRAY,
  })
}

The problem is that when you fallback on [] directly, it creates a new array on every render.

Zertz avatar May 01 '25 12:05 Zertz