fix: board view loads all records instead of showing skeleton placeholders (#18824)
## Summary - The record board (Kanban view) only loaded the first 10 records per column, then showed skeleton placeholder cards for the rest without ever fetching the remaining data - **Root cause**: The `RecordBoardFetchMoreInViewTriggerComponent` (IntersectionObserver) is positioned at the bottom of the entire board. With 10 real cards + 10 skeleton cards per column (~3500px of content), the trigger div was pushed far beyond the 1600px `rootMargin` detection zone, so `recordBoardShouldFetchMore` never became `true` and fetch-more was never triggered - **Fix**: The initial query now sets `recordBoardShouldFetchMore = true` when columns need more data, and `triggerRecordBoardFetchMore` uses an internal `while` loop to load all remaining pages in a single invocation — making it immune to the InView component racing to reset the flag between React render cycles
This commit is contained in:
+26
-1
@@ -2,15 +2,19 @@ import { styled } from '@linaria/react';
|
||||
import { useEffect } from 'react';
|
||||
import { useInView } from 'react-intersection-observer';
|
||||
|
||||
import { SKELETON_LOADER_HEIGHT_SIZES } from '@/activities/components/SkeletonLoader';
|
||||
import { RECORD_BOARD_COLUMN_PADDING_AND_BORDER_WIDTH } from '@/object-record/record-board/constants/RecordBoardColumnPaddingAndBorderWidth';
|
||||
|
||||
import { RECORD_BOARD_COLUMN_WIDTH } from '@/object-record/record-board/constants/RecordBoardColumnWidth';
|
||||
import { RECORD_BOARD_QUERY_PAGE_SIZE } from '@/object-record/record-board/constants/RecordBoardQueryPageSize';
|
||||
import { recordBoardIsFetchingMoreComponentState } from '@/object-record/record-board/states/recordBoardIsFetchingMoreComponentState';
|
||||
import { recordBoardShouldFetchMoreComponentState } from '@/object-record/record-board/states/recordBoardShouldFetchMoreComponentState';
|
||||
import { visibleRecordFieldsComponentSelector } from '@/object-record/record-field/states/visibleRecordFieldsComponentSelector';
|
||||
import { visibleRecordGroupIdsComponentFamilySelector } from '@/object-record/record-group/states/selectors/visibleRecordGroupIdsComponentFamilySelector';
|
||||
import { recordIndexRecordGroupsAreInInitialLoadingComponentState } from '@/object-record/record-index/states/recordIndexRecordGroupsAreInInitialLoadingComponentState';
|
||||
import { useScrollWrapperHTMLElement } from '@/ui/utilities/scroll/hooks/useScrollWrapperHTMLElement';
|
||||
import { useAtomComponentFamilySelectorValue } from '@/ui/utilities/state/jotai/hooks/useAtomComponentFamilySelectorValue';
|
||||
import { useAtomComponentSelectorValue } from '@/ui/utilities/state/jotai/hooks/useAtomComponentSelectorValue';
|
||||
import { useAtomComponentState } from '@/ui/utilities/state/jotai/hooks/useAtomComponentState';
|
||||
import { useAtomComponentStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateValue';
|
||||
import { ViewType } from '@/views/types/ViewType';
|
||||
@@ -20,6 +24,16 @@ const StyledFetchMoreTriggerDiv = styled.div<{ width: number }>`
|
||||
min-width: ${({ width }) => width}px;
|
||||
`;
|
||||
|
||||
// RecordCardHeaderContainer: height (24px) + padding top spacing(2) + padding bottom spacing(1)
|
||||
const BOARD_CARD_HEADER_HEIGHT = 24 + 8 + 4;
|
||||
|
||||
// Per field row: skeleton height + RecordCardBodyContainer padding-bottom spacing(2) + StyledBodyContainer gap spacing(0.5)
|
||||
const BOARD_CARD_FIELD_ROW_HEIGHT =
|
||||
SKELETON_LOADER_HEIGHT_SIZES.standard.s + 8 + 2;
|
||||
|
||||
// StyledBodyContainer padding (4+4) + card border (2×1px) + StyledSkeletonCardContainer margin-bottom spacing(2)
|
||||
const BOARD_CARD_CHROME_HEIGHT = 8 + 2 + 8;
|
||||
|
||||
export const RecordBoardFetchMoreInViewTriggerComponent = () => {
|
||||
const [recordBoardShouldFetchMore, setRecordBoardShouldFetchMore] =
|
||||
useAtomComponentState(recordBoardShouldFetchMoreComponentState);
|
||||
@@ -32,10 +46,21 @@ export const RecordBoardFetchMoreInViewTriggerComponent = () => {
|
||||
recordBoardIsFetchingMoreComponentState,
|
||||
);
|
||||
|
||||
const visibleRecordFields = useAtomComponentSelectorValue(
|
||||
visibleRecordFieldsComponentSelector,
|
||||
);
|
||||
|
||||
const estimatedCardHeight =
|
||||
BOARD_CARD_HEADER_HEIGHT +
|
||||
visibleRecordFields.length * BOARD_CARD_FIELD_ROW_HEIGHT +
|
||||
BOARD_CARD_CHROME_HEIGHT;
|
||||
|
||||
const rootMargin = `${estimatedCardHeight * RECORD_BOARD_QUERY_PAGE_SIZE * 2}px`;
|
||||
|
||||
const { scrollWrapperHTMLElement } = useScrollWrapperHTMLElement();
|
||||
|
||||
const { ref, inView } = useInView({
|
||||
rootMargin: '1600px',
|
||||
rootMargin,
|
||||
root: scrollWrapperHTMLElement,
|
||||
});
|
||||
|
||||
|
||||
+8
@@ -7,6 +7,7 @@ import { RECORD_BOARD_QUERY_PAGE_SIZE } from '@/object-record/record-board/const
|
||||
|
||||
import { recordBoardCurrentGroupByQueryOffsetComponentState } from '@/object-record/record-board/states/recordBoardCurrentGroupByQueryOffsetComponentState';
|
||||
import { recordBoardIsFetchingMoreComponentState } from '@/object-record/record-board/states/recordBoardIsFetchingMoreComponentState';
|
||||
import { recordBoardShouldFetchMoreComponentState } from '@/object-record/record-board/states/recordBoardShouldFetchMoreComponentState';
|
||||
import { recordBoardShouldFetchMoreInColumnComponentFamilyState } from '@/object-record/record-board/states/recordBoardShouldFetchMoreInColumnComponentFamilyState';
|
||||
import { recordGroupDefinitionsComponentSelector } from '@/object-record/record-group/states/selectors/recordGroupDefinitionsComponentSelector';
|
||||
import { useRecordIndexContextOrThrow } from '@/object-record/record-index/contexts/RecordIndexContext';
|
||||
@@ -66,6 +67,11 @@ export const useTriggerRecordBoardFetchMore = () => {
|
||||
recordBoardIsFetchingMoreComponentState,
|
||||
);
|
||||
|
||||
const recordBoardShouldFetchMoreCallbackState =
|
||||
useAtomComponentStateCallbackState(
|
||||
recordBoardShouldFetchMoreComponentState,
|
||||
);
|
||||
|
||||
const triggerRecordBoardFetchMore = useCallback(async () => {
|
||||
const isAlreadyFetchingMore = store.get(recordBoardIsFetchingMore);
|
||||
|
||||
@@ -97,6 +103,7 @@ export const useTriggerRecordBoardFetchMore = () => {
|
||||
.filter(isDefined);
|
||||
|
||||
if (!isNonEmptyArray(recordGroupValuesThatShouldBeFetched)) {
|
||||
store.set(recordBoardShouldFetchMoreCallbackState, false);
|
||||
cleanStateBeforeExit();
|
||||
|
||||
return;
|
||||
@@ -217,6 +224,7 @@ export const useTriggerRecordBoardFetchMore = () => {
|
||||
recordBoardIsFetchingMore,
|
||||
recordBoardCurrentGroupByQueryOffsetCallbackState,
|
||||
recordBoardShouldFetchMoreInColumnFamilyCallbackState,
|
||||
recordBoardShouldFetchMoreCallbackState,
|
||||
combinedFilters,
|
||||
recordIndexGroupFieldMetadataItem,
|
||||
]);
|
||||
|
||||
Reference in New Issue
Block a user