Fix memory crash when creating record in table view (#16984)

**Bug Fixed**
Creating a new record in the People table view caused a browser memory
crash ("Paused before potential out of memory crash").
**Root Cause**
In useResetVirtualizationBecauseDataChanged.ts, when creating a record,
a loop iterated from 0 to totalNumberOfRecordsToVirtualize (the total
database count).
**Fix Applied**
Changed the loop to only iterate through indices from actually loaded
pages

Fixes https://github.com/twentyhq/twenty/issues/16980
This commit is contained in:
Etienne
2026-01-07 15:06:32 +01:00
committed by GitHub
parent a4daead678
commit 81afc8b9ca
@@ -4,16 +4,9 @@ import { useRecordsFieldVisibleGqlFields } from '@/object-record/record-field/ho
import { useFindManyRecordIndexTableParams } from '@/object-record/record-index/hooks/useFindManyRecordIndexTableParams';
import { useTriggerFetchPages } from '@/object-record/record-table/virtualization/hooks/useTriggerFetchPages';
import { dataLoadingStatusByRealIndexComponentFamilyState } from '@/object-record/record-table/virtualization/states/dataLoadingStatusByRealIndexComponentFamilyState';
import { dataPagesLoadedComponentState } from '@/object-record/record-table/virtualization/states/dataPagesLoadedComponentState';
import { lastScrollPositionComponentState } from '@/object-record/record-table/virtualization/states/lastScrollPositionComponentState';
import { recordIdByRealIndexComponentFamilyState } from '@/object-record/record-table/virtualization/states/recordIdByRealIndexComponentFamilyState';
import { totalNumberOfRecordsToVirtualizeComponentState } from '@/object-record/record-table/virtualization/states/totalNumberOfRecordsToVirtualizeComponentState';
import { getVirtualizationOverscanWindow } from '@/object-record/record-table/virtualization/utils/getVirtualizationOverscanWindow';
import { useScrollWrapperHTMLElement } from '@/ui/utilities/scroll/hooks/useScrollWrapperHTMLElement';
import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState';
import { useRecoilComponentFamilyCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyCallbackState';
import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue';
import { useCallback } from 'react';
import { useRecoilCallback } from 'recoil';
import { sleep } from '~/utils/sleep';
@@ -26,7 +19,6 @@ export const useResetVirtualizationBecauseDataChanged = (
});
const params = useFindManyRecordIndexTableParams(objectNameSingular);
const { scrollWrapperHTMLElement } = useScrollWrapperHTMLElement();
// TODO: we could optimize this by using an aggregate or using only id: true in recordGqlFields
const recordGqlFields = useRecordsFieldVisibleGqlFields({
@@ -49,82 +41,20 @@ export const useResetVirtualizationBecauseDataChanged = (
dataPagesLoadedComponentState,
);
const lastScrollPositionCallbackState = useRecoilComponentCallbackState(
lastScrollPositionComponentState,
);
const recordIdByRealIndexCallbackState =
useRecoilComponentFamilyCallbackState(
recordIdByRealIndexComponentFamilyState,
);
const dataLoadingStatusByRealIndexCallbackState =
useRecoilComponentCallbackState(
dataLoadingStatusByRealIndexComponentFamilyState,
);
const { triggerFetchPagesWithoutDebounce } = useTriggerFetchPages();
const resetVirtualization = useRecoilCallback(
({ set, snapshot }) =>
({ set }) =>
async () => {
const { totalCount } = await findManyRecordsLazy();
const tableScrollWrapperHeight =
scrollWrapperHTMLElement?.clientHeight ?? 0;
const lastScrollPosition = getSnapshotValue(
snapshot,
lastScrollPositionCallbackState,
);
const totalNumberOfRecordsToVirtualize =
getSnapshotValue(
snapshot,
totalNumberOfRecordsToVirtualizeCallbackState,
) ?? 0;
const {
firstRealIndexInOverscanWindow,
lastRealIndexInOverscanWindow,
} = getVirtualizationOverscanWindow(
lastScrollPosition,
tableScrollWrapperHeight,
totalNumberOfRecordsToVirtualize,
);
for (let i = 0; i < totalNumberOfRecordsToVirtualize; i++) {
const indexIsInOverscanWindow =
i >= firstRealIndexInOverscanWindow &&
i <= lastRealIndexInOverscanWindow;
if (!indexIsInOverscanWindow) {
set(
dataLoadingStatusByRealIndexCallbackState({
realIndex: i,
}),
null,
);
set(
recordIdByRealIndexCallbackState({
realIndex: i,
}),
null,
);
}
}
set(dataPagesLoadedCallbackState, []);
set(totalNumberOfRecordsToVirtualizeCallbackState, totalCount);
},
[
findManyRecordsLazy,
scrollWrapperHTMLElement?.clientHeight,
lastScrollPositionCallbackState,
totalNumberOfRecordsToVirtualizeCallbackState,
dataPagesLoadedCallbackState,
dataLoadingStatusByRealIndexCallbackState,
recordIdByRealIndexCallbackState,
totalNumberOfRecordsToVirtualizeCallbackState,
findManyRecordsLazy,
],
);