Skip to content

Commit 0899165

Browse files
authored
Move state update listeners from constructor to componentDidMount (#28341)
* Move state update listeners from constructor to componentDidMount Signed-off-by: Michael Telatynski <[email protected]> * Iterate Signed-off-by: Michael Telatynski <[email protected]> * Iterate Signed-off-by: Michael Telatynski <[email protected]> --------- Signed-off-by: Michael Telatynski <[email protected]>
1 parent 2d9982f commit 0899165

File tree

72 files changed

+377
-309
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

72 files changed

+377
-309
lines changed

src/AsyncWrapper.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ export default class AsyncWrapper extends React.Component<IProps, IState> {
3737
public state: IState = {};
3838

3939
public componentDidMount(): void {
40+
this.unmounted = false;
4041
this.props.prom
4142
.then((result) => {
4243
if (this.unmounted) return;

src/async-components/views/dialogs/security/CreateSecretStorageDialog.tsx

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -117,8 +117,6 @@ export default class CreateSecretStorageDialog extends React.PureComponent<IProp
117117
// signing key upload as well. This avoids hitting the server to
118118
// test auth flows, which may be slow under high load.
119119
canUploadKeysWithPasswordOnly = true;
120-
} else {
121-
this.queryKeyUploadAuth();
122120
}
123121

124122
const keyFromCustomisations = ModuleRunner.instance.extensions.cryptoSetup.createSecretStorageKey();
@@ -140,8 +138,15 @@ export default class CreateSecretStorageDialog extends React.PureComponent<IProp
140138
passPhraseKeySelected,
141139
accountPassword,
142140
};
141+
}
143142

143+
public componentDidMount(): void {
144+
const keyFromCustomisations = ModuleRunner.instance.extensions.cryptoSetup.createSecretStorageKey();
144145
if (keyFromCustomisations) this.initExtension(keyFromCustomisations);
146+
147+
if (this.state.canUploadKeysWithPasswordOnly === null) {
148+
this.queryKeyUploadAuth();
149+
}
145150
}
146151

147152
private initExtension(keyFromCustomisations: Uint8Array): void {

src/async-components/views/dialogs/security/ExportE2eKeysDialog.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,10 @@ export default class ExportE2eKeysDialog extends React.Component<IProps, IState>
5656
};
5757
}
5858

59+
public componentDidMount(): void {
60+
this.unmounted = false;
61+
}
62+
5963
public componentWillUnmount(): void {
6064
this.unmounted = true;
6165
}

src/async-components/views/dialogs/security/ImportE2eKeysDialog.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,10 @@ export default class ImportE2eKeysDialog extends React.Component<IProps, IState>
6464
};
6565
}
6666

67+
public componentDidMount(): void {
68+
this.unmounted = false;
69+
}
70+
6771
public componentWillUnmount(): void {
6872
this.unmounted = true;
6973
}

src/components/structures/InteractiveAuth.tsx

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -90,8 +90,8 @@ interface IState {
9090

9191
export default class InteractiveAuthComponent<T> extends React.Component<InteractiveAuthProps<T>, IState> {
9292
private readonly authLogic: InteractiveAuth<T>;
93-
private readonly intervalId: number | null = null;
9493
private readonly stageComponent = createRef<IStageComponent>();
94+
private intervalId: number | null = null;
9595

9696
private unmounted = false;
9797

@@ -126,15 +126,17 @@ export default class InteractiveAuthComponent<T> extends React.Component<Interac
126126
AuthType.SsoUnstable,
127127
],
128128
});
129+
}
130+
131+
public componentDidMount(): void {
132+
this.unmounted = false;
129133

130134
if (this.props.poll) {
131135
this.intervalId = window.setInterval(() => {
132136
this.authLogic.poll();
133137
}, 2000);
134138
}
135-
}
136139

137-
public componentDidMount(): void {
138140
this.authLogic
139141
.attemptAuth()
140142
.then(async (result) => {

src/components/structures/LeftPanel.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -67,17 +67,17 @@ export default class LeftPanel extends React.Component<IProps, IState> {
6767
activeSpace: SpaceStore.instance.activeSpace,
6868
showBreadcrumbs: LeftPanel.breadcrumbsMode,
6969
};
70-
71-
BreadcrumbsStore.instance.on(UPDATE_EVENT, this.onBreadcrumbsUpdate);
72-
RoomListStore.instance.on(LISTS_UPDATE_EVENT, this.onBreadcrumbsUpdate);
73-
SpaceStore.instance.on(UPDATE_SELECTED_SPACE, this.updateActiveSpace);
7470
}
7571

7672
private static get breadcrumbsMode(): BreadcrumbsMode {
7773
return !BreadcrumbsStore.instance.visible ? BreadcrumbsMode.Disabled : BreadcrumbsMode.Legacy;
7874
}
7975

8076
public componentDidMount(): void {
77+
BreadcrumbsStore.instance.on(UPDATE_EVENT, this.onBreadcrumbsUpdate);
78+
RoomListStore.instance.on(LISTS_UPDATE_EVENT, this.onBreadcrumbsUpdate);
79+
SpaceStore.instance.on(UPDATE_SELECTED_SPACE, this.updateActiveSpace);
80+
8181
if (this.listContainerRef.current) {
8282
UIStore.instance.trackElementDimensions("ListContainer", this.listContainerRef.current);
8383
// Using the passive option to not block the main thread

src/components/structures/MatrixChat.tsx

Lines changed: 35 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -231,10 +231,10 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
231231
private prevWindowWidth: number;
232232
private voiceBroadcastResumer?: VoiceBroadcastResumer;
233233

234-
private readonly loggedInView: React.RefObject<LoggedInViewType>;
235-
private readonly dispatcherRef: string;
236-
private readonly themeWatcher: ThemeWatcher;
237-
private readonly fontWatcher: FontWatcher;
234+
private readonly loggedInView = createRef<LoggedInViewType>();
235+
private dispatcherRef?: string;
236+
private themeWatcher?: ThemeWatcher;
237+
private fontWatcher?: FontWatcher;
238238
private readonly stores: SdkContextClass;
239239

240240
public constructor(props: IProps) {
@@ -256,8 +256,6 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
256256
ready: false,
257257
};
258258

259-
this.loggedInView = createRef();
260-
261259
SdkConfig.put(this.props.config);
262260

263261
// Used by _viewRoom before getting state from sync
@@ -282,32 +280,10 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
282280
}
283281

284282
this.prevWindowWidth = UIStore.instance.windowWidth || 1000;
285-
UIStore.instance.on(UI_EVENTS.Resize, this.handleResize);
286-
287-
// For PersistentElement
288-
this.state.resizeNotifier.on("middlePanelResized", this.dispatchTimelineResize);
289-
290-
RoomNotificationStateStore.instance.on(UPDATE_STATUS_INDICATOR, this.onUpdateStatusIndicator);
291-
292-
this.dispatcherRef = dis.register(this.onAction);
293-
294-
this.themeWatcher = new ThemeWatcher();
295-
this.fontWatcher = new FontWatcher();
296-
this.themeWatcher.start();
297-
this.fontWatcher.start();
298283

299284
// object field used for tracking the status info appended to the title tag.
300285
// we don't do it as react state as i'm scared about triggering needless react refreshes.
301286
this.subTitleStatus = "";
302-
303-
initSentry(SdkConfig.get("sentry"));
304-
305-
if (!checkSessionLockFree()) {
306-
// another instance holds the lock; confirm its theft before proceeding
307-
setTimeout(() => this.setState({ view: Views.CONFIRM_LOCK_THEFT }), 0);
308-
} else {
309-
this.startInitSession();
310-
}
311287
}
312288

313289
/**
@@ -476,6 +452,29 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
476452
}
477453

478454
public componentDidMount(): void {
455+
UIStore.instance.on(UI_EVENTS.Resize, this.handleResize);
456+
457+
// For PersistentElement
458+
this.state.resizeNotifier.on("middlePanelResized", this.dispatchTimelineResize);
459+
460+
RoomNotificationStateStore.instance.on(UPDATE_STATUS_INDICATOR, this.onUpdateStatusIndicator);
461+
462+
this.dispatcherRef = dis.register(this.onAction);
463+
464+
this.themeWatcher = new ThemeWatcher();
465+
this.fontWatcher = new FontWatcher();
466+
this.themeWatcher.start();
467+
this.fontWatcher.start();
468+
469+
initSentry(SdkConfig.get("sentry"));
470+
471+
if (!checkSessionLockFree()) {
472+
// another instance holds the lock; confirm its theft before proceeding
473+
setTimeout(() => this.setState({ view: Views.CONFIRM_LOCK_THEFT }), 0);
474+
} else {
475+
this.startInitSession();
476+
}
477+
479478
window.addEventListener("resize", this.onWindowResized);
480479
}
481480

@@ -497,8 +496,8 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
497496
public componentWillUnmount(): void {
498497
Lifecycle.stopMatrixClient();
499498
dis.unregister(this.dispatcherRef);
500-
this.themeWatcher.stop();
501-
this.fontWatcher.stop();
499+
this.themeWatcher?.stop();
500+
this.fontWatcher?.stop();
502501
UIStore.destroy();
503502
this.state.resizeNotifier.removeListener("middlePanelResized", this.dispatchTimelineResize);
504503
window.removeEventListener("resize", this.onWindowResized);
@@ -1011,7 +1010,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
10111010

10121011
this.setStateForNewView(newState);
10131012
ThemeController.isLogin = true;
1014-
this.themeWatcher.recheck();
1013+
this.themeWatcher?.recheck();
10151014
this.notifyNewScreen(isMobileRegistration ? "mobile_register" : "register");
10161015
}
10171016

@@ -1088,7 +1087,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
10881087
},
10891088
() => {
10901089
ThemeController.isLogin = false;
1091-
this.themeWatcher.recheck();
1090+
this.themeWatcher?.recheck();
10921091
this.notifyNewScreen("room/" + presentedId, replaceLast);
10931092
},
10941093
);
@@ -1113,7 +1112,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
11131112
});
11141113
this.notifyNewScreen("welcome");
11151114
ThemeController.isLogin = true;
1116-
this.themeWatcher.recheck();
1115+
this.themeWatcher?.recheck();
11171116
}
11181117

11191118
private viewLogin(otherState?: any): void {
@@ -1123,7 +1122,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
11231122
});
11241123
this.notifyNewScreen("login");
11251124
ThemeController.isLogin = true;
1126-
this.themeWatcher.recheck();
1125+
this.themeWatcher?.recheck();
11271126
}
11281127

11291128
private viewHome(justRegistered = false): void {
@@ -1136,7 +1135,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
11361135
this.setPage(PageType.HomePage);
11371136
this.notifyNewScreen("home");
11381137
ThemeController.isLogin = false;
1139-
this.themeWatcher.recheck();
1138+
this.themeWatcher?.recheck();
11401139
}
11411140

11421141
private viewUser(userId: string, subAction: string): void {
@@ -1357,7 +1356,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
13571356
*/
13581357
private async onLoggedIn(): Promise<void> {
13591358
ThemeController.isLogin = false;
1360-
this.themeWatcher.recheck();
1359+
this.themeWatcher?.recheck();
13611360
StorageManager.tryPersistStorage();
13621361

13631362
await this.onShowPostLoginScreen();

src/components/structures/MessagePanel.tsx

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -240,13 +240,13 @@ export default class MessagePanel extends React.Component<IProps, IState> {
240240
private readReceiptsByUserId: Map<string, IReadReceiptForUser> = new Map();
241241

242242
private readonly _showHiddenEvents: boolean;
243-
private isMounted = false;
243+
private unmounted = false;
244244

245245
private readMarkerNode = createRef<HTMLLIElement>();
246246
private whoIsTyping = createRef<WhoIsTypingTile>();
247247
public scrollPanel = createRef<ScrollPanel>();
248248

249-
private readonly showTypingNotificationsWatcherRef: string;
249+
private showTypingNotificationsWatcherRef?: string;
250250
private eventTiles: Record<string, UnwrappedEventTile> = {};
251251

252252
// A map to allow groupers to maintain consistent keys even if their first event is uprooted due to back-pagination.
@@ -267,22 +267,21 @@ export default class MessagePanel extends React.Component<IProps, IState> {
267267
// and we check this in a hot code path. This is also cached in our
268268
// RoomContext, however we still need a fallback for roomless MessagePanels.
269269
this._showHiddenEvents = SettingsStore.getValue("showHiddenEventsInTimeline");
270+
}
270271

272+
public componentDidMount(): void {
273+
this.unmounted = false;
271274
this.showTypingNotificationsWatcherRef = SettingsStore.watchSetting(
272275
"showTypingNotifications",
273276
null,
274277
this.onShowTypingNotificationsChange,
275278
);
276-
}
277-
278-
public componentDidMount(): void {
279279
this.calculateRoomMembersCount();
280280
this.props.room?.currentState.on(RoomStateEvent.Update, this.calculateRoomMembersCount);
281-
this.isMounted = true;
282281
}
283282

284283
public componentWillUnmount(): void {
285-
this.isMounted = false;
284+
this.unmounted = true;
286285
this.props.room?.currentState.off(RoomStateEvent.Update, this.calculateRoomMembersCount);
287286
SettingsStore.unwatchSetting(this.showTypingNotificationsWatcherRef);
288287
this.readReceiptMap = {};
@@ -441,7 +440,7 @@ export default class MessagePanel extends React.Component<IProps, IState> {
441440
}
442441

443442
private isUnmounting = (): boolean => {
444-
return !this.isMounted;
443+
return this.unmounted;
445444
};
446445

447446
public get showHiddenEvents(): boolean {

src/components/structures/NonUrgentToastContainer.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,9 @@ export default class NonUrgentToastContainer extends React.PureComponent<IProps,
2525
this.state = {
2626
toasts: NonUrgentToastStore.instance.components,
2727
};
28+
}
2829

30+
public componentDidMount(): void {
2931
NonUrgentToastStore.instance.on(UPDATE_EVENT, this.onUpdateToasts);
3032
}
3133

src/components/structures/RoomSearch.tsx

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,9 @@ interface IProps {
2222
}
2323

2424
export default class RoomSearch extends React.PureComponent<IProps> {
25-
private readonly dispatcherRef: string;
26-
27-
public constructor(props: IProps) {
28-
super(props);
25+
private dispatcherRef?: string;
2926

27+
public componentDidMount(): void {
3028
this.dispatcherRef = defaultDispatcher.register(this.onAction);
3129
}
3230

0 commit comments

Comments
 (0)