diff --git a/.changeset/stop-silly-rerenders.md b/.changeset/stop-silly-rerenders.md new file mode 100644 index 000000000..ac6405db0 --- /dev/null +++ b/.changeset/stop-silly-rerenders.md @@ -0,0 +1,5 @@ +--- +default: patch +--- + +Fixed the entire timeline being rerendered every time you scroll :P diff --git a/src/app/features/room/RoomTimeline.tsx b/src/app/features/room/RoomTimeline.tsx index 45e00bc87..3062391dc 100644 --- a/src/app/features/room/RoomTimeline.tsx +++ b/src/app/features/room/RoomTimeline.tsx @@ -7,6 +7,7 @@ import { useMemo, useRef, useState, + memo, } from 'react'; import type { Editor } from 'slate'; import { useAtomValue, useSetAtom } from 'jotai'; @@ -48,7 +49,7 @@ import { useSpaceOptionally } from '$hooks/useSpace'; import { useMediaAuthentication } from '$hooks/useMediaAuthentication'; import { useIgnoredUsers } from '$hooks/useIgnoredUsers'; import { useImagePackRooms } from '$hooks/useImagePackRooms'; -import { settingsAtom, MessageLayout } from '$state/settings'; +import { settingsAtom, MessageLayout, type MessageSpacing } from '$state/settings'; import { useHiddenEventSettings, useSetting } from '$state/hooks/settings'; import { nicknamesAtom } from '$state/nicknames'; import { useRoomAbbreviationsContext } from '$hooks/useRoomAbbreviations'; @@ -103,6 +104,116 @@ const getDayDividerText = (ts: number) => { return timeDayMonthYear(ts); }; +const MemoizedTimelineItem = memo(function MemoizedTimelineItem({ + eventData, + index, + showLoadingPlaceholders, + canPaginateBack, + backPaginationJSX, + room, + messageLayout, + messageSpacing, + renderMatrixEvent, +}: { + eventData: ProcessedEvent | undefined; + index: number; + showLoadingPlaceholders: boolean; + canPaginateBack: boolean; + backPaginationJSX: ReactNode | undefined; + room: Room; + messageLayout: MessageLayout; + messageSpacing: MessageSpacing; + renderMatrixEvent: ReturnType; +}) { + if (showLoadingPlaceholders) { + return ( + + {messageLayout === MessageLayout.Compact ? : } + + ); + } + + if (!eventData) { + if (index === 0 && !canPaginateBack) { + return ( + + {backPaginationJSX} +
+ +
+
+ ); + } + if (index === 0) return {backPaginationJSX}; + return ; + } + + const renderedEvent = renderMatrixEvent( + eventData.mEvent.getType(), + typeof eventData.mEvent.getStateKey() === 'string', + eventData.id, + eventData.mEvent, + eventData.itemIndex, + eventData.timelineSet, + eventData.collapsed + ); + + const showDividers = renderedEvent !== null; + + const dividers = showDividers ? ( + <> + {eventData.willRenderDayDivider && ( + + + + {getDayDividerText(eventData.mEvent.getTs())} + + + + )} + {eventData.willRenderNewDivider && ( + + + + New Messages + + + + )} + + ) : null; + + if (index === 0) { + return ( + + {!canPaginateBack && ( +
+ +
+ )} + {backPaginationJSX} + {dividers} + {renderedEvent} +
+ ); + } + + return ( + + {dividers} + {renderedEvent} + + ); +}); + export type RoomTimelineProps = { room: Room; eventId?: string; @@ -903,99 +1014,20 @@ export function RoomTimeline({ }} onScroll={handleVListScroll} > - {(eventData, index) => { - if (showLoadingPlaceholders) { - return ( - - {messageLayout === MessageLayout.Compact ? ( - - ) : ( - - )} - - ); - } - - if (!eventData) { - if (index === 0 && !timelineSync.canPaginateBack) { - return ( - - {backPaginationJSX} -
- -
-
- ); - } - if (index === 0) return {backPaginationJSX}; - return ; - } - - const renderedEvent = renderMatrixEvent( - eventData.mEvent.getType(), - typeof eventData.mEvent.getStateKey() === 'string', - eventData.id, - eventData.mEvent, - eventData.itemIndex, - eventData.timelineSet, - eventData.collapsed - ); - - const showDividers = renderedEvent !== null; - - const dividers = showDividers ? ( - <> - {eventData.willRenderDayDivider && ( - - - - {getDayDividerText(eventData.mEvent.getTs())} - - - - )} - {eventData.willRenderNewDivider && ( - - - - New Messages - - - - )} - - ) : null; - - if (index === 0) { - return ( - - {!timelineSync.canPaginateBack && ( -
- -
- )} - {backPaginationJSX} - {dividers} - {renderedEvent} -
- ); - } - - return ( - - {dividers} - {renderedEvent} - - ); - }} + {(eventData, index) => ( + + )}