Recoil icon indicating copy to clipboard operation
Recoil copied to clipboard

Is there any demo about RecoilSyncLocalStorage?

Open cgc2109748 opened this issue 2 years ago • 3 comments

I can't find the RecoilSyncLocalStorage tga in recoil or recoil-sync

cgc2109748 avatar Jul 07 '22 03:07 cgc2109748

That adapter doesn't exist. Someone should really create a PR for it, people would find it useful.

drarmstr avatar Jul 08 '22 08:07 drarmstr

Here's my implementation if it helps, it supports syncing from other tabs as well:

export const localStorageStoreKey = 'localStorage'

const DEFAULT_VALUE = new DefaultValue()

const RecoilSyncLocalStorage: FC<{ children: ReactNode }> = ({ children }) => {
  const read: ReadItem = useCallback(
    (itemKey) => {
      if (typeof document === 'undefined') return DEFAULT_VALUE // SSR

      const item = localStorage.getItem(itemKey)

      let parsed: unknown

      try {
        parsed = item === null ? DEFAULT_VALUE : parseJSON(item)
      } catch {
        parsed = DEFAULT_VALUE
        console.warn({ itemKey, item }, 'parseJSON failed')
      }

      return parsed
    },
    [],
  )

  const write: WriteItems = useCallback(
    ({ diff }) => {
      if (typeof document === 'undefined') return // SSR

      for (const [key, value] of diff) {
        if (value instanceof DefaultValue) {
          localStorage.removeItem(key)
        } else {
          // reasons for setItem to fail: https://developer.mozilla.org/en-US/docs/Web/API/Storage/setItem#exceptions
          try {
            localStorage.setItem(key, JSON.stringify(value))
          } catch (err) {
            console.warn({ err, key, value }, 'localStorage.setItem failed')
          }
        }
      }
    },
    [],
  )

  const listen: ListenToItems = useCallback(
    ({ updateItem, updateAllKnownItems }) => {
      const onStorage = (event: StorageEvent) => {
        // ignore clear() calls
        if (event.storageArea === localStorage && event.key !== null) {
          let parsed: unknown
          try {
            parsed = event.newValue === null ? DEFAULT_VALUE : parseJSON(event.newValue)
          } catch {
            parsed = DEFAULT_VALUE
            console.warn({ event }, 'parseJSON failed')
          }

          updateItem(event.key, parsed)
        }
      }

      window.addEventListener('storage', onStorage)

      return () => window.removeEventListener('storage', onStorage)
    },
    [],
  )

  return (
    <RecoilSync storeKey={localStorageStoreKey} read={read} write={write} listen={listen}>
      {children}
    </RecoilSync>
  )
}

function parseJSON(value: string): unknown {
  return value === 'undefined' ? undefined : JSON.parse(value)
}

luishdz1010 avatar Sep 23 '22 02:09 luishdz1010

please update the docs about it 👁️

tmax22 avatar Feb 26 '24 15:02 tmax22