diff options
Diffstat (limited to 'src/state')
-rw-r--r-- | src/state/env.ts | 27 | ||||
-rw-r--r-- | src/state/index.ts | 30 | ||||
-rw-r--r-- | src/state/models/root-store.ts | 16 | ||||
-rw-r--r-- | src/state/storage.ts | 52 |
4 files changed, 125 insertions, 0 deletions
diff --git a/src/state/env.ts b/src/state/env.ts new file mode 100644 index 000000000..90a2cab5e --- /dev/null +++ b/src/state/env.ts @@ -0,0 +1,27 @@ +/** + * The environment is a place where services and shared dependencies between + * models live. They are made available to every model via dependency injection. + */ + +import {getEnv, IStateTreeNode} from 'mobx-state-tree' + +export class Environment { + constructor() {} + + async setup() {} +} + +/** + * Extension to the MST models that adds the environment property. + * Usage: + * + * .extend(withEnvironment) + * + */ +export const withEnvironment = (self: IStateTreeNode) => ({ + views: { + get environment() { + return getEnv<Environment>(self) + }, + }, +}) diff --git a/src/state/index.ts b/src/state/index.ts new file mode 100644 index 000000000..7c97ce294 --- /dev/null +++ b/src/state/index.ts @@ -0,0 +1,30 @@ +import {onSnapshot} from 'mobx-state-tree' +import {RootStoreModel, RootStore} from './models/root-store' +import {Environment} from './env' +import * as storage from './storage' + +const ROOT_STATE_STORAGE_KEY = 'root' + +export async function setupState() { + let rootStore: RootStore + let data: any + + const env = new Environment() + try { + data = (await storage.load(ROOT_STATE_STORAGE_KEY)) || {} + rootStore = RootStoreModel.create(data, env) + } catch (e) { + console.error('Failed to load state from storage', e) + rootStore = RootStoreModel.create({}, env) + } + + // track changes & save to storage + onSnapshot(rootStore, snapshot => + storage.save(ROOT_STATE_STORAGE_KEY, snapshot), + ) + + return rootStore +} + +export {useStores, RootStoreModel, RootStoreProvider} from './models/root-store' +export type {RootStore} from './models/root-store' diff --git a/src/state/models/root-store.ts b/src/state/models/root-store.ts new file mode 100644 index 000000000..164dfcced --- /dev/null +++ b/src/state/models/root-store.ts @@ -0,0 +1,16 @@ +/** + * The root store is the base of all modeled state. + */ + +import {Instance, SnapshotOut, types} from 'mobx-state-tree' +import {createContext, useContext} from 'react' + +export const RootStoreModel = types.model('RootStore').props({}) + +export interface RootStore extends Instance<typeof RootStoreModel> {} +export interface RootStoreSnapshot extends SnapshotOut<typeof RootStoreModel> {} + +// react context & hook utilities +const RootStoreContext = createContext<RootStore>({} as RootStore) +export const RootStoreProvider = RootStoreContext.Provider +export const useStores = () => useContext(RootStoreContext) diff --git a/src/state/storage.ts b/src/state/storage.ts new file mode 100644 index 000000000..dc5fb620f --- /dev/null +++ b/src/state/storage.ts @@ -0,0 +1,52 @@ +import AsyncStorage from '@react-native-async-storage/async-storage' + +export async function loadString(key: string): Promise<string | null> { + try { + return await AsyncStorage.getItem(key) + } catch { + // not sure why this would fail... even reading the RN docs I'm unclear + return null + } +} + +export async function saveString(key: string, value: string): Promise<boolean> { + try { + await AsyncStorage.setItem(key, value) + return true + } catch { + return false + } +} + +export async function load(key: string): Promise<any | null> { + try { + const str = await AsyncStorage.getItem(key) + if (typeof str !== 'string') { + return null + } + return JSON.parse(str) + } catch { + return null + } +} + +export async function save(key: string, value: any): Promise<boolean> { + try { + await AsyncStorage.setItem(key, JSON.stringify(value)) + return true + } catch { + return false + } +} + +export async function remove(key: string): Promise<void> { + try { + await AsyncStorage.removeItem(key) + } catch {} +} + +export async function clear(): Promise<void> { + try { + await AsyncStorage.clear() + } catch {} +} |