UNPKG

react-native-shared-state

Version:

Create shared states that can be connected to multiple react native components, allowing for simple global state management.

178 lines (177 loc) 5.99 kB
import { useMemo } from 'react'; import ExtendedError from 'extended_err'; import { MapCache } from './MapCache'; import { SharedState } from '../SharedState'; import { ComponentRegister } from '../SharedState/ComponentRegister'; import { StorageHandler } from '../SharedState/StorageHandler'; import { onMount, onUnMount, toArray, useReRender } from '../helpers'; export class SharedMap extends SharedState { constructor(key, options = {}) { const { debugLabel, defaultData = [] } = options; super({ __updateId: Symbol('Initial updater') }, { debugLabel }); this.elementRegister = new ComponentRegister(); this.mapCache = new MapCache(defaultData, key); super.debugger(this); } get(id) { return this.mapCache.current[id]; } get data() { return Object.values(this.mapCache.current); } get map() { return this.mapCache.current; } add(newElements, callback) { try { const newElementsArray = toArray(newElements); const updatedElements = this.mapCache.add(newElementsArray); const updated = !updatedElements.length; if (updated) { this.elementRegister.update(updatedElements); super.setState({ __updateId: Symbol('Initial updater') }); super.debugger({ send: updatedElements }); } } catch (error) { throw ExtendedError.transform(error, { name: 'State Error', code: 'ADD_DATA_ERROR', message: 'Error adding data', severity: 'HIGH', }); } if (callback) callback(); } refresh() { try { this.elementRegister.update(true); super.refresh(); } catch (error) { throw ExtendedError.transform(error, { name: 'State Error', code: 'REFRESH_MAP_ERROR', message: 'Refresh map error', severity: 'HIGH', }); } } remove(removeElements, callback) { try { const updated = this.mapCache.remove(toArray(removeElements)); if (updated) { super.setState({ __updateId: Symbol('Initial updater') }); super.debugger({ removeElements }); } } catch (error) { throw ExtendedError.transform(error, { name: 'State Error', code: 'REMOVE_DATA_ERROR', message: 'Error removing data', severity: 'HIGH', }); } // optional callback once complete if (callback) callback(); } reset() { throw new ExtendedError({ name: 'State Error', code: 'MAP_RESET_ERROR', message: 'Use resetData() to reset map', severity: 'HIGH', }); } resetData(resetMap) { try { this.mapCache.reset(resetMap); this.elementRegister.update(this.mapCache.current); super.reset(); super.debugger({ resetState: this.mapCache.current }); } catch (error) { throw ExtendedError.transform(error, { name: 'State Error', code: 'RESET_MAP_ERROR', message: 'Reset map error', severity: 'HIGH', }); } } setState() { throw new ExtendedError({ name: 'State Error', code: 'SET_DATA_ERROR', message: 'Cannot set state on SharedMap', severity: 'HIGH', }); } registerElement(component, ids) { const sharedMapId = Symbol('Shared Map ID'); function updateState() { component.setState({ [sharedMapId]: Symbol('Shared Map Updater') }); } this.elementRegister.register(component, ids, updateState); super.debugger({ registerElement: { component, ids } }); } unregisterElement(component) { this.elementRegister.unregister(component); super.debugger({ unregisterElement: { component } }); } registerList(component) { super.register(component, '__updateId'); } unregisterList(component) { super.unregister(component); } useElement(id) { const componentId = Symbol('Hook ID'); const reRender = useReRender(); onMount(() => { this.elementRegister.register(componentId, id, reRender); super.debugger({ registerHook: { componentId, id } }); }); onUnMount(() => { this.elementRegister.unregister(componentId); super.debugger({ unregisterHook: { componentId } }); }); return this.get(id); } useList() { super.useState('__updateId'); return { __updateId: this.state.__updateId, data: this.data }; } useMemo(memoFunction) { const { __updateId, data } = this.useList(); return useMemo(() => memoFunction(data), [__updateId]); } async initializeStorage(options) { this.dataStorageHandler = new StorageHandler(this.mapCache, options); try { this.resetData(await this.dataStorageHandler.get()); return true; } catch (error) { const storageError = ExtendedError.transform(error, { name: 'State Error', code: 'STORAGE_ERROR', message: 'Error loading from storage', severity: 'HIGH', }); this.resetData(); storageError.handle(); return false; } } save() { super.debugger(`Storing ${this.dataStorageHandler.options.storeName}`); return this.dataStorageHandler.save(); } toString() { return JSON.stringify(this.mapCache.current, null, 2); } }