@@ -695,11 +695,26 @@ function ReportActionsList({
695695 return isExpenseReport ( report ) || isIOUReport ( report ) || isInvoiceReport ( report ) ;
696696 } , [ parentReportAction , report , sortedVisibleReportActions ] ) ;
697697
698+ // Precompute a reportActionID → index map so renderItem can resolve the real index in O(1)
699+ // instead of scanning sortedVisibleReportActions with indexOf on every render.
700+ const actionIndexMap = useMemo ( ( ) => {
701+ const map = new Map < string , number > ( ) ;
702+ for ( const [ i , action ] of sortedVisibleReportActions . entries ( ) ) {
703+ map . set ( action . reportActionID , i ) ;
704+ }
705+ return map ;
706+ } , [ sortedVisibleReportActions ] ) ;
707+
698708 const renderItem = useCallback (
699709 ( { item : reportAction , index} : ListRenderItemInfo < OnyxTypes . ReportAction > ) => {
700710 const originalReportID = getOriginalReportID ( report . reportID , reportAction , reportActionsFromOnyx ) ;
701711 const showPreviousMessagesButton = reportAction . actionName === CONST . REPORT . ACTIONS . TYPE . CREATED && ! ! isConciergeSidePanel && ! ! showHiddenHistory && ! ! hasPreviousMessages ;
702712
713+ // Use the action's actual index in sortedVisibleReportActions rather than the FlashList-provided index,
714+ // because useFlashListScrollKey may slice the data for deep-link scroll positioning, making the
715+ // FlashList index offset from the full array and causing wrong displayAsGroup computation.
716+ const safeIndex = actionIndexMap . get ( reportAction . reportActionID ) ?? index ;
717+
703718 return (
704719 < >
705720 < ReportActionsListItemRenderer
@@ -711,8 +726,8 @@ function ReportActionsList({
711726 transactionThreadReport = { transactionThreadReport }
712727 linkedReportActionID = { linkedReportActionID }
713728 displayAsGroup = {
714- ! isConsecutiveChronosAutomaticTimerAction ( sortedVisibleReportActions , index , chatIncludesChronosWithID ( reportAction ?. reportID ) , isOffline ) &&
715- isConsecutiveActionMadeByPreviousActor ( sortedVisibleReportActions , index , isOffline )
729+ ! isConsecutiveChronosAutomaticTimerAction ( sortedVisibleReportActions , safeIndex , chatIncludesChronosWithID ( reportAction ?. reportID ) , isOffline ) &&
730+ isConsecutiveActionMadeByPreviousActor ( sortedVisibleReportActions , safeIndex , isOffline )
716731 }
717732 shouldHideThreadDividerLine = { shouldHideThreadDividerLine }
718733 shouldDisplayNewMarker = { reportAction . reportActionID === unreadMarkerReportActionID }
@@ -754,6 +769,7 @@ function ReportActionsList({
754769 isOffline ,
755770 transactionThreadReport ,
756771 linkedReportActionID ,
772+ actionIndexMap ,
757773 sortedVisibleReportActions ,
758774 shouldHideThreadDividerLine ,
759775 unreadMarkerReportActionID ,
@@ -847,14 +863,14 @@ function ReportActionsList({
847863 < View key = { action . reportActionID } >
848864 { renderItem ( {
849865 item : action ,
850- index : sortedVisibleReportActions . indexOf ( action ) ,
866+ index : actionIndexMap . get ( action . reportActionID ) ?? 0 ,
851867 } as ListRenderItemInfo < OnyxTypes . ReportAction > ) }
852868 </ View >
853869 ) ) }
854870 </ StaticReportActionsPreview >
855871 </ >
856872 ) ;
857- } , [ hideComposer , initialNumToRender , renderItem , shouldShowReportRecipientLocalTime , sortedVisibleReportActions , styles ] ) ;
873+ } , [ actionIndexMap , hideComposer , initialNumToRender , renderItem , shouldShowReportRecipientLocalTime , sortedVisibleReportActions , styles ] ) ;
858874
859875 const onStartReached = useCallback ( ( ) => {
860876 if ( ! isSearchTopmostFullScreenRoute ( ) ) {
0 commit comments