import React, { Context, ReactNode, useState, createContext, useEffect, useMemo } from 'react'; import { EventEmitter } from 'events'; import { isNull } from 'lodash'; import Debug from 'debug'; import { IStoreContext, defaultContext, useStore } from './store'; const debug = Debug('deepcase:store:local'); const localStorageEvent = new EventEmitter(); export const LocalContext = createContext(defaultContext); export const LocalStoreProvider = ({ context = LocalContext, children, }: { context?: Context; children?: ReactNode; }) => { const [useStore] = useState(() => { return function useStore( key: string, defaultValue: T, ): [T, (value: T) => any, () => any] { const memoDefaultValue = useMemo(() => defaultValue, []); const [value, _setValue] = useState(typeof(localStorage) === 'undefined' ? JSON.stringify(memoDefaultValue) : (localStorage.hasOwnProperty(key) ? localStorage.getItem(key) : JSON.stringify(memoDefaultValue))); useEffect( () => { const hasOwnProperty = localStorage.hasOwnProperty(key); debug('init', { key, defaultValue: memoDefaultValue, hasOwnProperty }); if (!hasOwnProperty) { const json = JSON.stringify(memoDefaultValue); localStorage.setItem(key, json); _setValue(json); } const fn = (value) => { const item = localStorage.getItem(key); if (typeof(item) === 'undefined' || isNull(item)) _setValue(JSON.stringify(memoDefaultValue)); else _setValue(value); }; localStorageEvent.on(key, fn); return () => { localStorageEvent.off(key, fn); }; }, [], ); const [setValue] = useState(() => (value) => { debug('setValue', { key, defaultValue: memoDefaultValue, value }); const json = JSON.stringify(value); localStorage.setItem(key, json); _setValue(json); localStorageEvent.emit(key, json); }); const [unsetValue] = useState(() => () => { debug('unsetValue', { key, defaultValue: memoDefaultValue }); localStorage.removeItem(key); localStorageEvent.emit(key, memoDefaultValue); }); return [JSON.parse(value), setValue, unsetValue]; }; }); return {children} ; }; export function useLocalStore(key: string, defaultValue: T, context = LocalContext) { return useStore(key, defaultValue, context); }