Move state update listeners from constructor to componentDidMount (#28341)

* Move state update listeners from constructor to componentDidMount

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Iterate

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Iterate

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

---------

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
This commit is contained in:
Michael Telatynski 2024-11-01 17:39:08 +00:00 committed by GitHub
parent 2d9982f9f0
commit 0899165d9e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
72 changed files with 377 additions and 309 deletions

View file

@ -68,11 +68,13 @@ export default class AppsDrawer extends React.Component<IProps, IState> {
};
this.resizer = this.createResizer();
this.props.resizeNotifier.on("isResizing", this.onIsResizing);
}
public componentDidMount(): void {
this.unmounted = false;
this.props.resizeNotifier.on("isResizing", this.onIsResizing);
ScalarMessaging.startListening();
WidgetLayoutStore.instance.on(WidgetLayoutStore.emissionForRoom(this.props.room), this.updateApps);
this.dispatcherRef = dis.register(this.onAction);

View file

@ -128,10 +128,10 @@ export default class BasicMessageEditor extends React.Component<IProps, IState>
private lastCaret!: DocumentOffset;
private lastSelection: ReturnType<typeof cloneSelection> | null = null;
private readonly useMarkdownHandle: string;
private readonly emoticonSettingHandle: string;
private readonly shouldShowPillAvatarSettingHandle: string;
private readonly surroundWithHandle: string;
private useMarkdownHandle?: string;
private emoticonSettingHandle?: string;
private shouldShowPillAvatarSettingHandle?: string;
private surroundWithHandle?: string;
private readonly historyManager = new HistoryManager();
public constructor(props: IProps) {
@ -145,28 +145,7 @@ export default class BasicMessageEditor extends React.Component<IProps, IState>
const ua = navigator.userAgent.toLowerCase();
this.isSafari = ua.includes("safari/") && !ua.includes("chrome/");
this.useMarkdownHandle = SettingsStore.watchSetting(
"MessageComposerInput.useMarkdown",
null,
this.configureUseMarkdown,
);
this.emoticonSettingHandle = SettingsStore.watchSetting(
"MessageComposerInput.autoReplaceEmoji",
null,
this.configureEmoticonAutoReplace,
);
this.configureEmoticonAutoReplace();
this.shouldShowPillAvatarSettingHandle = SettingsStore.watchSetting(
"Pill.shouldShowPillAvatar",
null,
this.configureShouldShowPillAvatar,
);
this.surroundWithHandle = SettingsStore.watchSetting(
"MessageComposerInput.surroundWith",
null,
this.surroundWithSettingChanged,
);
}
public componentDidUpdate(prevProps: IProps): void {
@ -737,6 +716,27 @@ export default class BasicMessageEditor extends React.Component<IProps, IState>
}
public componentDidMount(): void {
this.useMarkdownHandle = SettingsStore.watchSetting(
"MessageComposerInput.useMarkdown",
null,
this.configureUseMarkdown,
);
this.emoticonSettingHandle = SettingsStore.watchSetting(
"MessageComposerInput.autoReplaceEmoji",
null,
this.configureEmoticonAutoReplace,
);
this.shouldShowPillAvatarSettingHandle = SettingsStore.watchSetting(
"Pill.shouldShowPillAvatar",
null,
this.configureShouldShowPillAvatar,
);
this.surroundWithHandle = SettingsStore.watchSetting(
"MessageComposerInput.surroundWith",
null,
this.surroundWithSettingChanged,
);
const model = this.props.model;
model.setUpdateCallback(this.updateEditorState);
const partCreator = model.partCreator;

View file

@ -124,7 +124,7 @@ class EditMessageComposer extends React.Component<IEditMessageComposerProps, ISt
public declare context: React.ContextType<typeof RoomContext>;
private readonly editorRef = createRef<BasicMessageComposer>();
private readonly dispatcherRef: string;
private dispatcherRef?: string;
private readonly replyToEvent?: MatrixEvent;
private model!: EditorModel;
@ -140,7 +140,9 @@ class EditMessageComposer extends React.Component<IEditMessageComposerProps, ISt
this.state = {
saveDisabled: !isRestored || !this.isContentModified(editContent["m.new_content"]!),
};
}
public componentDidMount(): void {
window.addEventListener("beforeunload", this.saveStoredEditorState);
this.dispatcherRef = dis.register(this.onAction);
}

View file

@ -386,6 +386,7 @@ export class UnwrappedEventTile extends React.Component<EventTileProps, IState>
}
public componentDidMount(): void {
this.unmounted = false;
this.suppressReadReceiptAnimation = false;
const client = MatrixClientPeg.safeGet();
if (!this.props.forExport) {

View file

@ -72,7 +72,7 @@ interface IState {
export default class MemberList extends React.Component<IProps, IState> {
private readonly showPresence: boolean;
private mounted = false;
private unmounted = false;
public static contextType = SDKContext;
public declare context: React.ContextType<typeof SDKContext>;
@ -82,8 +82,6 @@ export default class MemberList extends React.Component<IProps, IState> {
super(props, context);
this.state = this.getMembersState([], []);
this.showPresence = context?.memberListStore.isPresenceEnabled() ?? true;
this.mounted = true;
this.listenForMembersChanges();
}
private listenForMembersChanges(): void {
@ -102,11 +100,13 @@ export default class MemberList extends React.Component<IProps, IState> {
}
public componentDidMount(): void {
this.unmounted = false;
this.listenForMembersChanges();
this.updateListNow(true);
}
public componentWillUnmount(): void {
this.mounted = false;
this.unmounted = true;
const cli = MatrixClientPeg.get();
if (cli) {
cli.removeListener(RoomStateEvent.Update, this.onRoomStateUpdate);
@ -205,7 +205,7 @@ export default class MemberList extends React.Component<IProps, IState> {
// XXX: exported for tests
public async updateListNow(showLoadingSpinner?: boolean): Promise<void> {
if (!this.mounted) {
if (this.unmounted) {
return;
}
if (showLoadingSpinner) {
@ -215,7 +215,7 @@ export default class MemberList extends React.Component<IProps, IState> {
this.props.roomId,
this.props.searchQuery,
);
if (!this.mounted) {
if (this.unmounted) {
return;
}
this.setState({

View file

@ -134,9 +134,6 @@ export class MessageComposer extends React.Component<IProps, IState> {
super(props, context);
this.context = context; // otherwise React will only set it prior to render due to type def above
VoiceRecordingStore.instance.on(UPDATE_EVENT, this.onVoiceStoreUpdate);
window.addEventListener("beforeunload", this.saveWysiwygEditorState);
const isWysiwygLabEnabled = SettingsStore.getValue<boolean>("feature_wysiwyg_composer");
let isRichTextEnabled = true;
let initialComposerContent = "";
@ -145,13 +142,6 @@ export class MessageComposer extends React.Component<IProps, IState> {
if (wysiwygState) {
isRichTextEnabled = wysiwygState.isRichText;
initialComposerContent = wysiwygState.content;
if (wysiwygState.replyEventId) {
dis.dispatch({
action: "reply_to_event",
event: this.props.room.findEventById(wysiwygState.replyEventId),
context: this.context.timelineRenderingType,
});
}
}
}
@ -171,11 +161,6 @@ export class MessageComposer extends React.Component<IProps, IState> {
};
this.instanceId = instanceCount++;
SettingsStore.monitorSetting("MessageComposerInput.showStickersButton", null);
SettingsStore.monitorSetting("MessageComposerInput.showPollsButton", null);
SettingsStore.monitorSetting(Features.VoiceBroadcast, null);
SettingsStore.monitorSetting("feature_wysiwyg_composer", null);
}
private get editorStateKey(): string {
@ -248,6 +233,25 @@ export class MessageComposer extends React.Component<IProps, IState> {
}
public componentDidMount(): void {
VoiceRecordingStore.instance.on(UPDATE_EVENT, this.onVoiceStoreUpdate);
window.addEventListener("beforeunload", this.saveWysiwygEditorState);
if (this.state.isWysiwygLabEnabled) {
const wysiwygState = this.restoreWysiwygEditorState();
if (wysiwygState?.replyEventId) {
dis.dispatch({
action: "reply_to_event",
event: this.props.room.findEventById(wysiwygState.replyEventId),
context: this.context.timelineRenderingType,
});
}
}
SettingsStore.monitorSetting("MessageComposerInput.showStickersButton", null);
SettingsStore.monitorSetting("MessageComposerInput.showPollsButton", null);
SettingsStore.monitorSetting(Features.VoiceBroadcast, null);
SettingsStore.monitorSetting("feature_wysiwyg_composer", null);
this.dispatcherRef = dis.register(this.onAction);
this.waitForOwnMember();
UIStore.instance.trackElementDimensions(`MessageComposer${this.instanceId}`, this.ref.current!);

View file

@ -44,15 +44,23 @@ interface IState {
}
export default class NotificationBadge extends React.PureComponent<XOR<IProps, IClickableProps>, IState> {
private countWatcherRef: string;
private countWatcherRef?: string;
public constructor(props: IProps) {
super(props);
this.props.notification.on(NotificationStateEvents.Update, this.onNotificationUpdate);
this.state = {
showCounts: SettingsStore.getValue("Notifications.alwaysShowBadgeCounts", this.roomId),
};
}
private get roomId(): string | null {
// We should convert this to null for safety with the SettingsStore
return this.props.roomId || null;
}
public componentDidMount(): void {
this.props.notification.on(NotificationStateEvents.Update, this.onNotificationUpdate);
this.countWatcherRef = SettingsStore.watchSetting(
"Notifications.alwaysShowBadgeCounts",
@ -61,11 +69,6 @@ export default class NotificationBadge extends React.PureComponent<XOR<IProps, I
);
}
private get roomId(): string | null {
// We should convert this to null for safety with the SettingsStore
return this.props.roomId || null;
}
public componentWillUnmount(): void {
SettingsStore.unwatchSetting(this.countWatcherRef);
this.props.notification.off(NotificationStateEvents.Update, this.onNotificationUpdate);

View file

@ -60,7 +60,7 @@ const RoomBreadcrumbTile: React.FC<{ room: Room; onClick: (ev: ButtonEvent) => v
};
export default class RoomBreadcrumbs extends React.PureComponent<IProps, IState> {
private isMounted = true;
private unmounted = false;
private toolbar = createRef<HTMLDivElement>();
public constructor(props: IProps) {
@ -70,17 +70,20 @@ export default class RoomBreadcrumbs extends React.PureComponent<IProps, IState>
doAnimation: true, // technically we want animation on mount, but it won't be perfect
skipFirst: false, // render the thing, as boring as it is
};
}
public componentDidMount(): void {
this.unmounted = false;
BreadcrumbsStore.instance.on(UPDATE_EVENT, this.onBreadcrumbsUpdate);
}
public componentWillUnmount(): void {
this.isMounted = false;
this.unmounted = true;
BreadcrumbsStore.instance.off(UPDATE_EVENT, this.onBreadcrumbsUpdate);
}
private onBreadcrumbsUpdate = (): void => {
if (!this.isMounted) return;
if (this.unmounted) return;
// We need to trick the CSSTransition component into updating, which means we need to
// tell it to not animate, then to animate a moment later. This causes two updates

View file

@ -94,7 +94,6 @@ export class RoomTile extends React.PureComponent<ClassProps, State> {
// generatePreview() will return nothing if the user has previews disabled
messagePreview: null,
};
this.generatePreview();
this.notificationState = RoomNotificationStateStore.instance.getRoomState(this.props.room);
this.roomProps = EchoChamber.forRoom(this.props.room);
@ -147,6 +146,8 @@ export class RoomTile extends React.PureComponent<ClassProps, State> {
}
public componentDidMount(): void {
this.generatePreview();
// when we're first rendered (or our sublist is expanded) make sure we are visible if we're active
if (this.state.selected) {
this.scrollIntoView();

View file

@ -255,7 +255,7 @@ export class SendMessageComposer extends React.Component<ISendMessageComposerPro
private readonly editorRef = createRef<BasicMessageComposer>();
private model: EditorModel;
private currentlyComposedEditorState: SerializedPart[] | null = null;
private dispatcherRef: string;
private dispatcherRef?: string;
private sendHistoryManager: SendHistoryManager;
public static defaultProps = {
@ -275,15 +275,17 @@ export class SendMessageComposer extends React.Component<ISendMessageComposerPro
);
}
window.addEventListener("beforeunload", this.saveStoredEditorState);
const partCreator = new CommandPartCreator(this.props.room, this.props.mxClient);
const parts = this.restoreStoredEditorState(partCreator) || [];
this.model = new EditorModel(parts, partCreator);
this.dispatcherRef = dis.register(this.onAction);
this.sendHistoryManager = new SendHistoryManager(this.props.room.roomId, "mx_cider_history_");
}
public componentDidMount(): void {
window.addEventListener("beforeunload", this.saveStoredEditorState);
this.dispatcherRef = dis.register(this.onAction);
}
public componentDidUpdate(prevProps: ISendMessageComposerProps): void {
const replyingToThread = this.props.relation?.key === THREAD_RELATION_TYPE.name;
const differentEventTarget = this.props.relation?.event_id !== prevProps.relation?.event_id;