Add state management
This commit is contained in:
parent
92ca49ab9a
commit
d6942bffab
17 changed files with 340 additions and 133 deletions
27
src/state/env.ts
Normal file
27
src/state/env.ts
Normal file
|
@ -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)
|
||||
},
|
||||
},
|
||||
})
|
30
src/state/index.ts
Normal file
30
src/state/index.ts
Normal file
|
@ -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'
|
16
src/state/models/root-store.ts
Normal file
16
src/state/models/root-store.ts
Normal file
|
@ -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)
|
52
src/state/storage.ts
Normal file
52
src/state/storage.ts
Normal file
|
@ -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 {}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue