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
JavaScript
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);
}
}