From 9a22fdfaa1e88d12cb6e526dd1e4ae9d1e85201a Mon Sep 17 00:00:00 2001 From: Ryan Albrecht Date: Tue, 15 Jul 2025 16:01:37 -0700 Subject: [PATCH] fix(feedback): Fix a case where duplicate items can be rendered in the list --- static/app/components/feedback/list/feedbackList.tsx | 4 +++- static/app/components/infiniteList/infiniteListItems.tsx | 8 ++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/static/app/components/feedback/list/feedbackList.tsx b/static/app/components/feedback/list/feedbackList.tsx index 3515ffb726f16f..e0482d9a0c1c9f 100644 --- a/static/app/components/feedback/list/feedbackList.tsx +++ b/static/app/components/feedback/list/feedbackList.tsx @@ -35,8 +35,9 @@ export default function FeedbackList() { enabled: Boolean(listQueryKey), }); + // Deduplicated issues. In case one page overlaps with another. const issues = useMemo( - () => uniqBy(queryResult.data?.pages.flatMap(([pageData]) => pageData) ?? [], 'id'), + () => uniqBy(queryResult.data?.pages.flatMap(result => result[0]) ?? [], 'id'), [queryResult.data?.pages] ); const checkboxState = useListItemCheckboxContext({ @@ -57,6 +58,7 @@ export default function FeedbackList() { loadingMessage={() => } > + deduplicateItems={items => uniqBy(items, 'id')} estimateSize={() => 24} queryResult={queryResult} itemRenderer={({item}) => ( diff --git a/static/app/components/infiniteList/infiniteListItems.tsx b/static/app/components/infiniteList/infiniteListItems.tsx index 85006623f01ef5..1f5a3f5ad994ce 100644 --- a/static/app/components/infiniteList/infiniteListItems.tsx +++ b/static/app/components/infiniteList/infiniteListItems.tsx @@ -24,6 +24,7 @@ interface Props { >, {fetchNextPage: () => Promise} >; + deduplicateItems?: (items: Data[]) => Data[]; emptyMessage?: () => React.ReactNode; estimateSize?: () => number; loadingCompleteMessage?: () => React.ReactNode; @@ -32,16 +33,19 @@ interface Props { } export default function InfiniteListItems({ + deduplicateItems = _ => _, + emptyMessage = EmptyMessage, estimateSize, itemRenderer, - emptyMessage = EmptyMessage, loadingCompleteMessage = LoadingCompleteMessage, loadingMoreMessage = LoadingMoreMessage, overscan, queryResult, }: Props) { const {data, hasNextPage, isFetchingNextPage, fetchNextPage} = queryResult; - const loadedRows = data ? data.pages.flatMap(d => d[0]) : []; + const loadedRows = deduplicateItems( + data ? data.pages.flatMap(result => result[0]) : [] + ); const parentRef = useRef(null); const rowVirtualizer = useVirtualizer({