Skip to content

Commit a3820d6

Browse files
committed
Avoid TimelinePanel re-renders on duplicate sync state events
1 parent f0eb954 commit a3820d6

2 files changed

Lines changed: 33 additions & 0 deletions

File tree

apps/web/src/components/structures/TimelinePanel.tsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -897,8 +897,13 @@ class TimelinePanel extends React.Component<IProps, IState> {
897897
this.forceUpdate();
898898
};
899899

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.
900904
private onSync = (clientSyncState: SyncState, prevState: SyncState | null, data?: object): void => {
901905
if (this.unmounted) return;
906+
if (clientSyncState === this.state.clientSyncState) return;
902907
this.setState({ clientSyncState });
903908
};
904909

apps/web/test/unit-tests/components/structures/TimelinePanel-test.tsx

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ Please see LICENSE files in the repository root for full details.
88

99
import { render, waitFor, screen, act, cleanup } from "jest-matrix-react";
1010
import {
11+
ClientEvent,
1112
ReceiptType,
1213
EventTimelineSet,
1314
EventType,
@@ -19,6 +20,7 @@ import {
1920
RoomEvent,
2021
RoomMember,
2122
RoomState,
23+
SyncState,
2224
TimelineWindow,
2325
EventTimeline,
2426
FeatureSupport,
@@ -483,6 +485,32 @@ describe("TimelinePanel", () => {
483485
});
484486
});
485487

488+
it("does not re-render MessagePanel for duplicate sync state events", async () => {
489+
const [client, room, events] = setupTestData();
490+
let timelinePanel: TimelinePanel | null = null;
491+
492+
render(
493+
<TimelinePanel
494+
{...getProps(room, events)}
495+
ref={(ref) => {
496+
timelinePanel = ref;
497+
}}
498+
/>,
499+
clientAndSDKContextRenderOptions(client, sdkContext),
500+
);
501+
await flushPromises();
502+
await waitFor(() => expect(timelinePanel).toBeTruthy());
503+
504+
const setStateSpy = jest.spyOn(timelinePanel!, "setState");
505+
506+
await act(async () => {
507+
client.emit(ClientEvent.Sync, SyncState.Syncing, SyncState.Syncing);
508+
await flushPromises();
509+
});
510+
511+
expect(setStateSpy).not.toHaveBeenCalled();
512+
});
513+
486514
describe("onRoomTimeline", () => {
487515
it("ignores events for other timelines", () => {
488516
const [client, room, events] = setupTestData();

0 commit comments

Comments
 (0)