Fix instances of setState calls after unmount
							parent
							
								
									e9d56d4f13
								
							
						
					
					
						commit
						7c3c04d340
					
				|  | @ -916,6 +916,7 @@ export default class RoomView extends React.Component<IProps, IState> { | |||
|     // called when state.room is first initialised (either at initial load,
 | ||||
|     // after a successful peek, or after we join the room).
 | ||||
|     private onRoomLoaded = (room: Room) => { | ||||
|         if (this.unmounted) return; | ||||
|         // Attach a widget store listener only when we get a room
 | ||||
|         WidgetLayoutStore.instance.on(WidgetLayoutStore.emissionForRoom(room), this.onWidgetLayoutChange); | ||||
|         this.onWidgetLayoutChange(); // provoke an update
 | ||||
|  | @ -930,9 +931,9 @@ export default class RoomView extends React.Component<IProps, IState> { | |||
|     }; | ||||
| 
 | ||||
|     private async calculateRecommendedVersion(room: Room) { | ||||
|         this.setState({ | ||||
|             upgradeRecommendation: await room.getRecommendedVersion(), | ||||
|         }); | ||||
|         const upgradeRecommendation = await room.getRecommendedVersion(); | ||||
|         if (this.unmounted) return; | ||||
|         this.setState({ upgradeRecommendation }); | ||||
|     } | ||||
| 
 | ||||
|     private async loadMembersIfJoined(room: Room) { | ||||
|  | @ -1022,23 +1023,19 @@ export default class RoomView extends React.Component<IProps, IState> { | |||
|     }; | ||||
| 
 | ||||
|     private async updateE2EStatus(room: Room) { | ||||
|         if (!this.context.isRoomEncrypted(room.roomId)) { | ||||
|             return; | ||||
|         } | ||||
|         if (!this.context.isCryptoEnabled()) { | ||||
|             // If crypto is not currently enabled, we aren't tracking devices at all,
 | ||||
|             // so we don't know what the answer is. Let's error on the safe side and show
 | ||||
|             // a warning for this case.
 | ||||
|             this.setState({ | ||||
|                 e2eStatus: E2EStatus.Warning, | ||||
|             }); | ||||
|             return; | ||||
|         if (!this.context.isRoomEncrypted(room.roomId)) return; | ||||
| 
 | ||||
|         // If crypto is not currently enabled, we aren't tracking devices at all,
 | ||||
|         // so we don't know what the answer is. Let's error on the safe side and show
 | ||||
|         // a warning for this case.
 | ||||
|         let e2eStatus = E2EStatus.Warning; | ||||
|         if (this.context.isCryptoEnabled()) { | ||||
|             /* At this point, the user has encryption on and cross-signing on */ | ||||
|             e2eStatus = await shieldStatusForRoom(this.context, room); | ||||
|         } | ||||
| 
 | ||||
|         /* At this point, the user has encryption on and cross-signing on */ | ||||
|         this.setState({ | ||||
|             e2eStatus: await shieldStatusForRoom(this.context, room), | ||||
|         }); | ||||
|         if (this.unmounted) return; | ||||
|         this.setState({ e2eStatus }); | ||||
|     } | ||||
| 
 | ||||
|     private onAccountData = (event: MatrixEvent) => { | ||||
|  |  | |||
|  | @ -1051,6 +1051,8 @@ class TimelinePanel extends React.Component<IProps, IState> { | |||
|             { windowLimit: this.props.timelineCap }); | ||||
| 
 | ||||
|         const onLoaded = () => { | ||||
|             if (this.unmounted) return; | ||||
| 
 | ||||
|             // clear the timeline min-height when
 | ||||
|             // (re)loading the timeline
 | ||||
|             if (this.messagePanel.current) { | ||||
|  | @ -1092,6 +1094,8 @@ class TimelinePanel extends React.Component<IProps, IState> { | |||
|         }; | ||||
| 
 | ||||
|         const onError = (error) => { | ||||
|             if (this.unmounted) return; | ||||
| 
 | ||||
|             this.setState({ timelineLoading: false }); | ||||
|             console.error( | ||||
|                 `Error loading timeline panel at ${eventId}: ${error}`, | ||||
|  |  | |||
|  | @ -38,7 +38,7 @@ interface IState { | |||
| @replaceableComponent("views.messages.SenderProfile") | ||||
| export default class SenderProfile extends React.Component<IProps, IState> { | ||||
|     static contextType = MatrixClientContext; | ||||
|     private unmounted: boolean; | ||||
|     private unmounted = false; | ||||
| 
 | ||||
|     constructor(props: IProps) { | ||||
|         super(props); | ||||
|  | @ -51,7 +51,6 @@ export default class SenderProfile extends React.Component<IProps, IState> { | |||
|     } | ||||
| 
 | ||||
|     componentDidMount() { | ||||
|         this.unmounted = false; | ||||
|         this.updateRelatedGroups(); | ||||
| 
 | ||||
|         if (this.state.userGroups.length === 0) { | ||||
|  | @ -67,30 +66,24 @@ export default class SenderProfile extends React.Component<IProps, IState> { | |||
|     } | ||||
| 
 | ||||
|     private async getPublicisedGroups() { | ||||
|         if (!this.unmounted) { | ||||
|             const userGroups = await FlairStore.getPublicisedGroupsCached( | ||||
|                 this.context, this.props.mxEvent.getSender(), | ||||
|             ); | ||||
|             this.setState({ userGroups }); | ||||
|         } | ||||
|         const userGroups = await FlairStore.getPublicisedGroupsCached(this.context, this.props.mxEvent.getSender()); | ||||
|         if (this.unmounted) return; | ||||
|         this.setState({ userGroups }); | ||||
|     } | ||||
| 
 | ||||
|     private onRoomStateEvents = (event: MatrixEvent) => { | ||||
|         if (event.getType() === 'm.room.related_groups' && | ||||
|             event.getRoomId() === this.props.mxEvent.getRoomId() | ||||
|         ) { | ||||
|         if (event.getType() === 'm.room.related_groups' && event.getRoomId() === this.props.mxEvent.getRoomId()) { | ||||
|             this.updateRelatedGroups(); | ||||
|         } | ||||
|     }; | ||||
| 
 | ||||
|     private updateRelatedGroups() { | ||||
|         if (this.unmounted) return; | ||||
|         const room = this.context.getRoom(this.props.mxEvent.getRoomId()); | ||||
|         if (!room) return; | ||||
| 
 | ||||
|         const relatedGroupsEvent = room.currentState.getStateEvents('m.room.related_groups', ''); | ||||
|         this.setState({ | ||||
|             relatedGroups: relatedGroupsEvent ? relatedGroupsEvent.getContent().groups || [] : [], | ||||
|             relatedGroups: relatedGroupsEvent?.getContent().groups || [], | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|  |  | |||
|  | @ -76,6 +76,7 @@ export default class AppearanceUserSettingsTab extends React.Component<IProps, I | |||
|     private readonly MESSAGE_PREVIEW_TEXT = _t("Hey you. You're the best!"); | ||||
| 
 | ||||
|     private themeTimer: number; | ||||
|     private unmounted = false; | ||||
| 
 | ||||
|     constructor(props: IProps) { | ||||
|         super(props); | ||||
|  | @ -101,6 +102,7 @@ export default class AppearanceUserSettingsTab extends React.Component<IProps, I | |||
|         const client = MatrixClientPeg.get(); | ||||
|         const userId = client.getUserId(); | ||||
|         const profileInfo = await client.getProfileInfo(userId); | ||||
|         if (this.unmounted) return; | ||||
| 
 | ||||
|         this.setState({ | ||||
|             userId, | ||||
|  | @ -109,6 +111,10 @@ export default class AppearanceUserSettingsTab extends React.Component<IProps, I | |||
|         }); | ||||
|     } | ||||
| 
 | ||||
|     componentWillUnmount() { | ||||
|         this.unmounted = true; | ||||
|     } | ||||
| 
 | ||||
|     private calculateThemeState(): IThemeState { | ||||
|         // We have to mirror the logic from ThemeWatcher.getEffectiveTheme so we
 | ||||
|         // show the right values for things.
 | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	 Michael Telatynski
						Michael Telatynski