@@ -24,7 +24,7 @@ import {
2424 type MatrixClient ,
2525 type Relations ,
2626 type MatrixError ,
27- type SyncState ,
27+ SyncState ,
2828 TimelineWindow ,
2929 Thread ,
3030 ThreadEvent ,
@@ -192,9 +192,6 @@ interface IState {
192192 backPaginating : boolean ;
193193 forwardPaginating : boolean ;
194194
195- // cache of matrixClient.getSyncState() (but from the 'sync' event)
196- clientSyncState : SyncState | null ;
197-
198195 // should the event tiles have twelve hour times
199196 isTwelveHour : boolean ;
200197
@@ -251,12 +248,17 @@ class TimelinePanel extends React.Component<IProps, IState> {
251248 // A map of <callId, LegacyCallEventGrouper>
252249 private callEventGroupers = new Map < string , LegacyCallEventGrouper > ( ) ;
253250 private initialReadMarkerId : string | null = null ;
251+ private syncImpliesForwardPaginating : boolean ;
254252
255253 public constructor ( props : IProps , context : React . ContextType < typeof RoomContext > ) {
256254 super ( props , context ) ;
257255
258256 debuglog ( "mounting" ) ;
259257
258+ this . syncImpliesForwardPaginating = TimelinePanel . isSyncForwardPaginating (
259+ MatrixClientPeg . safeGet ( ) . getSyncState ( ) ,
260+ ) ;
261+
260262 // XXX: we could track RM per TimelineSet rather than per Room.
261263 // but for now we just do it per room for simplicity.
262264 if ( this . props . manageReadMarkers ) {
@@ -278,7 +280,6 @@ class TimelinePanel extends React.Component<IProps, IState> {
278280 readMarkerEventId : this . initialReadMarkerId ,
279281 backPaginating : false ,
280282 forwardPaginating : false ,
281- clientSyncState : MatrixClientPeg . safeGet ( ) . getSyncState ( ) ,
282283 isTwelveHour : SettingsStore . getValue ( "showTwelveHourTimestamps" ) ,
283284 alwaysShowTimestamps : SettingsStore . getValue ( "alwaysShowTimestamps" ) ,
284285 readMarkerInViewThresholdMs : SettingsStore . getValue ( "readMarkerInViewThresholdMs" ) ,
@@ -897,16 +898,19 @@ class TimelinePanel extends React.Component<IProps, IState> {
897898 this . forceUpdate ( ) ;
898899 } ;
899900
900- // The SDK intentionally emits duplicate Sync events such as SYNCING -> SYNCING
901- // on each successful /sync so consumers can react to every sync loop. TimelinePanel
902- // only uses this state to drive loading UI, so duplicate values do not change what
903- // we render and would otherwise cause unnecessary MessagePanel re-renders.
904901 private onSync = ( clientSyncState : SyncState , prevState : SyncState | null , data ?: object ) : void => {
905902 if ( this . unmounted ) return ;
906- if ( clientSyncState === this . state . clientSyncState ) return ;
907- this . setState ( { clientSyncState } ) ;
903+ const nextSyncImpliesForwardPaginating = TimelinePanel . isSyncForwardPaginating ( clientSyncState ) ;
904+ if ( nextSyncImpliesForwardPaginating === this . syncImpliesForwardPaginating ) return ;
905+
906+ this . syncImpliesForwardPaginating = nextSyncImpliesForwardPaginating ;
907+ this . forceUpdate ( ) ;
908908 } ;
909909
910+ private static isSyncForwardPaginating ( syncState : SyncState | null ) : boolean {
911+ return syncState === SyncState . Prepared || syncState === SyncState . Catchup ;
912+ }
913+
910914 private readMarkerTimeout ( readMarkerPosition : number | null ) : number {
911915 return readMarkerPosition === 0
912916 ? ( this . context ?. readMarkerInViewThresholdMs ?? this . state . readMarkerInViewThresholdMs )
@@ -1837,8 +1841,7 @@ class TimelinePanel extends React.Component<IProps, IState> {
18371841
18381842 // If the state is PREPARED or CATCHUP, we're still waiting for the js-sdk to sync with
18391843 // the HS and fetch the latest events, so we are effectively forward paginating.
1840- const forwardPaginating =
1841- this . state . forwardPaginating || [ "PREPARED" , "CATCHUP" ] . includes ( this . state . clientSyncState ! ) ;
1844+ const forwardPaginating = this . state . forwardPaginating || this . syncImpliesForwardPaginating ;
18421845 const events = this . state . events ;
18431846 return (
18441847 < MessagePanel
0 commit comments