From aa7594cfac6afd2d3dd9303b3e5fb8f7dcb2cd82 Mon Sep 17 00:00:00 2001 From: Owen Delahoy Date: Mon, 6 Feb 2023 23:59:09 +0900 Subject: [PATCH 1/3] feat: use storage events to synchronize across windows --- src/index.ts | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/src/index.ts b/src/index.ts index 45d1871..f4e30fb 100644 --- a/src/index.ts +++ b/src/index.ts @@ -9,6 +9,7 @@ export interface PersistStorage { export interface PersistConfiguration { key?: string storage?: PersistStorage + synchronizeWindows?: boolean } /** @@ -27,9 +28,13 @@ export const recoilPersist = ( } } - const { key = 'recoil-persist', storage = localStorage } = config + const { + key = 'recoil-persist', + storage = localStorage, + synchronizeWindows = true, + } = config - const persistAtom: AtomEffect = ({ onSet, node, trigger, setSelf }) => { + const persistAtom: AtomEffect = ({ onSet, node, trigger, setSelf, resetSelf }) => { if (trigger === 'get') { const state = getState() if (typeof state.then === 'function') { @@ -52,6 +57,21 @@ export const recoilPersist = ( updateState(newValue, state, node.key, isReset) } }) + + if(synchronizeWindows) { + const onStorageEvent = (e: StorageEvent) => { + if(e.key == key) { + const state = parseState(e.newValue) + if(node.key in state) { + setSelf(state[node.key]) + } else { + resetSelf() + } + } + } + window.addEventListener('storage', onStorageEvent) + return () => window.removeEventListener('storage', onStorageEvent) + } } const updateState = ( @@ -84,8 +104,8 @@ export const recoilPersist = ( return {} } - const parseState = (state: string) => { - if (state === undefined) { + const parseState = (state?: string | null) => { + if (!state) { return {} } try { From dcc1bceeb29a8cd64ed1a1720e90da6ddb545ff6 Mon Sep 17 00:00:00 2001 From: Owen Delahoy Date: Tue, 7 Feb 2023 00:18:19 +0900 Subject: [PATCH 2/3] feat: allow configuration of how to add and remove StorageEvent listeners --- src/index.ts | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/src/index.ts b/src/index.ts index f4e30fb..d5bc962 100644 --- a/src/index.ts +++ b/src/index.ts @@ -6,10 +6,15 @@ export interface PersistStorage { getItem(key: string): null | string | Promise } +export interface StorageEvent { + readonly key?: string | null; + readonly newValue?: string | null; +} + export interface PersistConfiguration { key?: string storage?: PersistStorage - synchronizeWindows?: boolean + addStorageListener?: (listener: (e: StorageEvent) => void) => ReturnType> } /** @@ -18,6 +23,9 @@ export interface PersistConfiguration { * @param config Optional configuration object * @param config.key Used as key in local storage, defaults to `recoil-persist` * @param config.storage Local storage to use, defaults to `localStorage` + * @param config.addStorageListener Optional method to listen to storage events + * enabling external events to trigger application updates + * defaults to `localStorage` events synchronizing multiple windows */ export const recoilPersist = ( config: PersistConfiguration = {}, @@ -31,7 +39,10 @@ export const recoilPersist = ( const { key = 'recoil-persist', storage = localStorage, - synchronizeWindows = true, + addStorageListener = (listener) => { + window.addEventListener('storage', listener) + return () => window.removeEventListener('storage', listener) + }, } = config const persistAtom: AtomEffect = ({ onSet, node, trigger, setSelf, resetSelf }) => { @@ -58,8 +69,8 @@ export const recoilPersist = ( } }) - if(synchronizeWindows) { - const onStorageEvent = (e: StorageEvent) => { + if(addStorageListener) { + const removeStorageListener = addStorageListener((e: StorageEvent) => { if(e.key == key) { const state = parseState(e.newValue) if(node.key in state) { @@ -68,9 +79,8 @@ export const recoilPersist = ( resetSelf() } } - } - window.addEventListener('storage', onStorageEvent) - return () => window.removeEventListener('storage', onStorageEvent) + }); + return removeStorageListener; } } From f9232d2f8292e8a7cdd288bbd48af621afd6d70b Mon Sep 17 00:00:00 2001 From: Owen Delahoy Date: Tue, 7 Feb 2023 00:41:09 +0900 Subject: [PATCH 3/3] fix: allow addStorageListener to be null to disable synchronization --- src/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/index.ts b/src/index.ts index d5bc962..0207264 100644 --- a/src/index.ts +++ b/src/index.ts @@ -14,7 +14,7 @@ export interface StorageEvent { export interface PersistConfiguration { key?: string storage?: PersistStorage - addStorageListener?: (listener: (e: StorageEvent) => void) => ReturnType> + addStorageListener?: ((listener: (e: StorageEvent) => void) => ReturnType>) | null } /**