diff --git a/theatre/studio/src/Studio.ts b/theatre/studio/src/Studio.ts index 2b6e6dd..a1f15fd 100644 --- a/theatre/studio/src/Studio.ts +++ b/theatre/studio/src/Studio.ts @@ -28,6 +28,8 @@ import {getAllPossibleAssetIDs} from '@theatre/shared/utils/assets' import {notify} from './notify' import type {RafDriverPrivateAPI} from '@theatre/core/rafDrivers' +const DEFAULT_PERSISTENCE_KEY = 'theatre-0.4' + export type CoreExports = typeof _coreExports const UIConstructorModule = @@ -159,7 +161,7 @@ export class Studio { } const storeOpts: Parameters[0] = { - persistenceKey: 'theatre-0.4', + persistenceKey: DEFAULT_PERSISTENCE_KEY, usePersistentStorage: true, } @@ -515,4 +517,8 @@ export class Studio { }, } } + + clearPersistentStorage(persistenceKey = DEFAULT_PERSISTENCE_KEY) { + this._store.__experimental_clearPersistentStorage(persistenceKey) + } } diff --git a/theatre/studio/src/StudioStore/StudioStore.ts b/theatre/studio/src/StudioStore/StudioStore.ts index f8ba364..a189640 100644 --- a/theatre/studio/src/StudioStore/StudioStore.ts +++ b/theatre/studio/src/StudioStore/StudioStore.ts @@ -20,7 +20,10 @@ import type {Atom, Pointer} from '@theatre/dataverse' import type {Draft} from 'immer' import {createDraft, finishDraft} from 'immer' import type {Store} from 'redux' -import {persistStateOfStudio} from './persistStateOfStudio' +import { + __experimental_clearPersistentStorage, + persistStateOfStudio, +} from './persistStateOfStudio' import type {OnDiskState} from '@theatre/core/projects/store/storeTypes' import {generateDiskStateRevision} from './generateDiskStateRevision' @@ -89,6 +92,13 @@ export default class StudioStore { return this._reduxStore.getState() } + __experimental_clearPersistentStorage( + persistenceKey: string, + ): FullStudioState { + __experimental_clearPersistentStorage(this._reduxStore, persistenceKey) + return this.getState() + } + /** * This method causes the store to start the history from scratch. This is useful * for testing and development where you want to explicitly provide a state to the diff --git a/theatre/studio/src/StudioStore/persistStateOfStudio.ts b/theatre/studio/src/StudioStore/persistStateOfStudio.ts index 06c430a..bd61ea6 100644 --- a/theatre/studio/src/StudioStore/persistStateOfStudio.ts +++ b/theatre/studio/src/StudioStore/persistStateOfStudio.ts @@ -5,6 +5,11 @@ import type {FullStudioState} from '@theatre/studio/store/index' import debounce from 'lodash-es/debounce' import type {Store} from 'redux' +const lastStateByStore = new WeakMap< + Store, + StudioPersistentState +>() + export const persistStateOfStudio = ( reduxStore: Store, onInitialize: () => void, @@ -14,16 +19,16 @@ export const persistStateOfStudio = ( reduxStore.dispatch(studioActions.replacePersistentState(s)) } - const storageKey = localStoragePrefix + '.persistent' + const storageKey = getStorageKey(localStoragePrefix) const getState = () => reduxStore.getState().$persistent loadFromPersistentStorage() - let lastState = getState() const persist = () => { const newState = getState() + const lastState = lastStateByStore.get(reduxStore) if (newState === lastState) return - lastState = newState + lastStateByStore.set(reduxStore, newState) localStorage.setItem(storageKey, JSON.stringify(newState)) } reduxStore.subscribe(debounce(persist, 1000)) @@ -54,3 +59,22 @@ export const persistStateOfStudio = ( } } } + +export const __experimental_clearPersistentStorage = ( + reduxStore: Store, + localStoragePrefix: string, +) => { + // This removes the persisted state from localStorage, + // while also preventing the current state from being persisted on window unload. + // Once the new storage PR lands, this method won't be needed anymore. + const storageKey = getStorageKey(localStoragePrefix) + const currentState = reduxStore.getState().$persistent + localStorage.removeItem(storageKey) + // prevent the current state from being persistent on window unload, + // unless further state changes are made. + lastStateByStore.set(reduxStore, currentState) +} + +function getStorageKey(localStoragePrefix: string) { + return localStoragePrefix + '.persistent' +} diff --git a/theatre/studio/src/TheatreStudio.ts b/theatre/studio/src/TheatreStudio.ts index 597b525..ade4342 100644 --- a/theatre/studio/src/TheatreStudio.ts +++ b/theatre/studio/src/TheatreStudio.ts @@ -409,6 +409,14 @@ export interface IStudio { * Disables the play/pause keyboard shortcut (spacebar) */ __experimental_enablePlayPauseKeyboardShortcut(): void + /** + * Clears persistent storage and ensures that the current state will not be + * saved on window unload. Further changes to state will continue writing to + * persistent storage, if enabled during initialization. + * + * @param persistenceKey - same persistencyKey as in `studio.initialize(opts)`, if any + */ + __experimental_clearPersistentStorage(persistenceKey?: string): void } } @@ -446,6 +454,9 @@ export default class TheatreStudio implements IStudio { // see __experimental_disblePlayPauseKeyboardShortcut() __experimental_enablePlayPauseKeyboardShortcut() }, + __experimental_clearPersistentStorage(persistenceKey?: string): void { + return getStudio().clearPersistentStorage(persistenceKey) + }, } /**