fix: improve deinit logic and flow
This commit is contained in:
@@ -196,10 +196,17 @@ export class ApplicationView extends PureComponent<Props, State> {
|
||||
};
|
||||
|
||||
render() {
|
||||
if (this.application['dealloced'] === true) {
|
||||
console.error('Attempting to render dealloced application');
|
||||
return <div></div>;
|
||||
}
|
||||
|
||||
const renderAppContents = !this.state.needsUnlock && this.state.launched;
|
||||
|
||||
return (
|
||||
<PremiumModalProvider state={this.appState.features}>
|
||||
<PremiumModalProvider state={this.appState?.features}>
|
||||
<div className={this.platformString + ' main-ui-view sn-component'}>
|
||||
{!this.state.needsUnlock && this.state.launched && (
|
||||
{renderAppContents && (
|
||||
<div
|
||||
id="app"
|
||||
className={this.state.appClass + ' app app-column-container'}
|
||||
@@ -215,23 +222,25 @@ export class ApplicationView extends PureComponent<Props, State> {
|
||||
</div>
|
||||
)}
|
||||
|
||||
{!this.state.needsUnlock && this.state.launched && (
|
||||
<Footer
|
||||
application={this.application}
|
||||
applicationGroup={this.props.mainApplicationGroup}
|
||||
/>
|
||||
{renderAppContents && (
|
||||
<>
|
||||
<Footer
|
||||
application={this.application}
|
||||
applicationGroup={this.props.mainApplicationGroup}
|
||||
/>
|
||||
|
||||
<SessionsModal
|
||||
application={this.application}
|
||||
appState={this.appState}
|
||||
/>
|
||||
|
||||
<PreferencesViewWrapper
|
||||
appState={this.appState}
|
||||
application={this.application}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
|
||||
<SessionsModal
|
||||
application={this.application}
|
||||
appState={this.appState}
|
||||
/>
|
||||
|
||||
<PreferencesViewWrapper
|
||||
appState={this.appState}
|
||||
application={this.application}
|
||||
/>
|
||||
|
||||
{this.state.challenges.map((challenge) => {
|
||||
return (
|
||||
<div className="sk-modal">
|
||||
@@ -245,15 +254,19 @@ export class ApplicationView extends PureComponent<Props, State> {
|
||||
);
|
||||
})}
|
||||
|
||||
<NotesContextMenu
|
||||
application={this.application}
|
||||
appState={this.appState}
|
||||
/>
|
||||
{renderAppContents && (
|
||||
<>
|
||||
<NotesContextMenu
|
||||
application={this.application}
|
||||
appState={this.appState}
|
||||
/>
|
||||
|
||||
<PurchaseFlowWrapper
|
||||
application={this.application}
|
||||
appState={this.appState}
|
||||
/>
|
||||
<PurchaseFlowWrapper
|
||||
application={this.application}
|
||||
appState={this.appState}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</PremiumModalProvider>
|
||||
);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { FeaturesState } from '@/ui_models/app_state/features_state';
|
||||
import { observer } from 'mobx-react-lite';
|
||||
import { FunctionalComponent } from 'preact';
|
||||
import { useCallback, useContext, useState } from 'preact/hooks';
|
||||
import { useContext } from 'preact/hooks';
|
||||
import { createContext } from 'react';
|
||||
import { PremiumFeaturesModal } from '../PremiumFeaturesModal';
|
||||
|
||||
|
||||
@@ -93,7 +93,6 @@ export class AppState {
|
||||
|
||||
private readonly tagChangedDisposer: IReactionDisposer;
|
||||
|
||||
/* @ngInject */
|
||||
constructor(application: WebApplication, private bridge: Bridge) {
|
||||
this.application = application;
|
||||
this.notes = new NotesState(
|
||||
@@ -171,18 +170,39 @@ export class AppState {
|
||||
storage.remove(StorageKey.ShowBetaWarning);
|
||||
this.noAccountWarning.reset();
|
||||
}
|
||||
(this.application as unknown) = undefined;
|
||||
this.actionsMenu.reset();
|
||||
this.unsubApp?.();
|
||||
this.unsubApp = undefined;
|
||||
this.observers.length = 0;
|
||||
|
||||
this.appEventObserverRemovers.forEach((remover) => remover());
|
||||
this.features.deinit();
|
||||
this.appEventObserverRemovers.length = 0;
|
||||
|
||||
this.features.deinit();
|
||||
(this.features as unknown) = undefined;
|
||||
|
||||
this.webAppEventDisposer?.();
|
||||
this.webAppEventDisposer = undefined;
|
||||
|
||||
(this.quickSettingsMenu as unknown) = undefined;
|
||||
(this.accountMenu as unknown) = undefined;
|
||||
(this.actionsMenu as unknown) = undefined;
|
||||
(this.preferences as unknown) = undefined;
|
||||
(this.purchaseFlow as unknown) = undefined;
|
||||
(this.noteTags as unknown) = undefined;
|
||||
(this.sync as unknown) = undefined;
|
||||
(this.searchOptions as unknown) = undefined;
|
||||
(this.notes as unknown) = undefined;
|
||||
(this.features as unknown) = undefined;
|
||||
(this.tags as unknown) = undefined;
|
||||
(this.notesView as unknown) = undefined;
|
||||
|
||||
document.removeEventListener('visibilitychange', this.onVisibilityChange);
|
||||
this.onVisibilityChange = undefined;
|
||||
|
||||
this.tagChangedDisposer();
|
||||
(this.tagChangedDisposer as unknown) = undefined;
|
||||
}
|
||||
|
||||
openSessionsModal(): void {
|
||||
|
||||
@@ -39,8 +39,8 @@ export type WebEventObserver = (event: WebAppEvent) => void;
|
||||
|
||||
export class WebApplication extends SNApplication {
|
||||
private webServices!: WebServices;
|
||||
public noteControllerGroup: NoteGroupController;
|
||||
private webEventObservers: WebEventObserver[] = [];
|
||||
public noteControllerGroup: NoteGroupController;
|
||||
public iconsController: IconsController;
|
||||
|
||||
constructor(
|
||||
@@ -70,28 +70,26 @@ export class WebApplication extends SNApplication {
|
||||
this.iconsController = new IconsController();
|
||||
}
|
||||
|
||||
/** @override */
|
||||
deinit(source: DeinitSource): void {
|
||||
for (const service of Object.values(this.webServices)) {
|
||||
if ('deinit' in service) {
|
||||
service.deinit?.(source);
|
||||
super.deinit(source);
|
||||
try {
|
||||
for (const service of Object.values(this.webServices)) {
|
||||
if ('deinit' in service) {
|
||||
service.deinit?.(source);
|
||||
}
|
||||
(service as any).application = undefined;
|
||||
}
|
||||
(service as any).application = undefined;
|
||||
}
|
||||
this.webServices = {} as WebServices;
|
||||
this.noteControllerGroup.deinit();
|
||||
this.iconsController.deinit();
|
||||
this.webEventObservers.length = 0;
|
||||
/**
|
||||
* Allow any pending renders to complete before destroying the global
|
||||
* application instance and all its services
|
||||
*/
|
||||
setTimeout(() => {
|
||||
super.deinit(source);
|
||||
this.webServices = {} as WebServices;
|
||||
this.noteControllerGroup.deinit();
|
||||
this.iconsController.deinit();
|
||||
this.webEventObservers.length = 0;
|
||||
|
||||
if (source === DeinitSource.SignOut) {
|
||||
this.bridge.onSignOut();
|
||||
}
|
||||
}, 0);
|
||||
} catch (error) {
|
||||
console.error('Error while deiniting application', error);
|
||||
}
|
||||
}
|
||||
|
||||
setWebServices(services: WebServices): void {
|
||||
|
||||
@@ -84,7 +84,7 @@
|
||||
"@reach/tooltip": "^0.16.2",
|
||||
"@standardnotes/components": "1.7.0",
|
||||
"@standardnotes/features": "1.29.0",
|
||||
"@standardnotes/snjs": "2.52.1",
|
||||
"@standardnotes/snjs": "2.52.2",
|
||||
"@standardnotes/settings": "^1.11.3",
|
||||
"@standardnotes/sncrypto-web": "1.6.2",
|
||||
"mobx": "^6.3.5",
|
||||
|
||||
@@ -2650,10 +2650,10 @@
|
||||
buffer "^6.0.3"
|
||||
libsodium-wrappers "^0.7.9"
|
||||
|
||||
"@standardnotes/snjs@2.52.1":
|
||||
version "2.52.1"
|
||||
resolved "https://registry.yarnpkg.com/@standardnotes/snjs/-/snjs-2.52.1.tgz#00e2e1f7eaeef2c95b6830470031496e48ff4b83"
|
||||
integrity sha512-U35dangXmhl1uEnPcDmWrRlqHyT/N5KIE5izT8w0xkhrWpc5a62j+m0u2uJNYU7C00d6ERqVWXeHCDsdSXTx8A==
|
||||
"@standardnotes/snjs@2.52.2":
|
||||
version "2.52.2"
|
||||
resolved "https://registry.yarnpkg.com/@standardnotes/snjs/-/snjs-2.52.2.tgz#34d1edd3028aa860648548292291d6ecf8666a5f"
|
||||
integrity sha512-5w2RXSquTmyYNSyKgEYqmLLqbHyYCsyrqfWlL0nuQ//hBFcf8OUbsY+Ys132TodpGZn637Al+kygoZxGBVcSyA==
|
||||
dependencies:
|
||||
"@standardnotes/auth" "^3.15.4"
|
||||
"@standardnotes/common" "^1.9.0"
|
||||
|
||||
Reference in New Issue
Block a user