@@ -13,6 +13,14 @@ export const useGetMore = (rid: string, isJumpingToMessage: boolean) => {
1313 const ref = useSafeRefCallback (
1414 useCallback (
1515 ( element : HTMLElement ) => {
16+ // Observers (MutationObserver, ResizeObserver) fire during the initial mount cascade
17+ // as messages are inserted and the virtualizer measures itself. At that point scrollTop
18+ // is still 0 because scroll-to-bottom hasn't run yet, which made checkPositionAndGetMore
19+ // pull a second history page immediately after the first. Gate observer-driven calls on
20+ // real user input (wheel / touch / scroll-affecting keys); programmatic scroll does not
21+ // flip this flag.
22+ let userInteracted = false ;
23+
1624 const checkPositionAndGetMore = withThrottling ( { wait : 100 } ) ( async ( ) => {
1725 if ( ! element . isConnected ) {
1826 return ;
@@ -57,32 +65,58 @@ export const useGetMore = (rid: string, isJumpingToMessage: boolean) => {
5765 }
5866 } ) ;
5967
60- const mutationObserver = new MutationObserver ( ( mutations ) => {
61- mutations . forEach ( ( ) => {
62- checkPositionAndGetMore ( ) ;
63- } ) ;
64- } ) ;
68+ const gatedCheck = ( ) => {
69+ // Surrounding-messages fetch (when navigating to ?msg=...) needs to fire once on
70+ // the initial observer pass before the user has interacted.
71+ const allowedByJumpToMessage = ! ! msgId && ! RoomHistoryManager . isLoaded ( rid ) ;
72+ if ( ! userInteracted && ! allowedByJumpToMessage ) {
73+ return ;
74+ }
75+ checkPositionAndGetMore ( ) ;
76+ } ;
6577
78+ const mutationObserver = new MutationObserver ( gatedCheck ) ;
6679 mutationObserver . observe ( element , { childList : true , subtree : true } ) ;
6780
68- const observer = new ResizeObserver ( ( ) => {
69- checkPositionAndGetMore ( ) ;
70- } ) ;
71-
81+ const observer = new ResizeObserver ( gatedCheck ) ;
7282 observer . observe ( element ) ;
7383
74- const handleScroll = function ( ) {
84+ const markInteracted = ( ) => {
85+ userInteracted = true ;
86+ } ;
87+
88+ const handleKeydown = ( e : KeyboardEvent ) => {
89+ if (
90+ e . key === 'PageUp' ||
91+ e . key === 'PageDown' ||
92+ e . key === 'ArrowUp' ||
93+ e . key === 'ArrowDown' ||
94+ e . key === 'Home' ||
95+ e . key === 'End'
96+ ) {
97+ userInteracted = true ;
98+ }
99+ } ;
100+
101+ const handleScroll = ( ) => {
102+ if ( ! userInteracted ) {
103+ return ;
104+ }
75105 checkPositionAndGetMore ( ) ;
76106 } ;
77107
78- element . addEventListener ( 'scroll' , handleScroll , {
79- passive : true ,
80- } ) ;
108+ element . addEventListener ( 'wheel' , markInteracted , { passive : true } ) ;
109+ element . addEventListener ( 'touchmove' , markInteracted , { passive : true } ) ;
110+ element . addEventListener ( 'keydown' , handleKeydown ) ;
111+ element . addEventListener ( 'scroll' , handleScroll , { passive : true } ) ;
81112
82113 return ( ) => {
83114 observer . disconnect ( ) ;
84115 mutationObserver . disconnect ( ) ;
85116 checkPositionAndGetMore . cancel ( ) ;
117+ element . removeEventListener ( 'wheel' , markInteracted ) ;
118+ element . removeEventListener ( 'touchmove' , markInteracted ) ;
119+ element . removeEventListener ( 'keydown' , handleKeydown ) ;
86120 element . removeEventListener ( 'scroll' , handleScroll ) ;
87121 } ;
88122 } ,
0 commit comments