···1+/**
2+ * The environment is a place where services and shared dependencies between
3+ * models live. They are made available to every model via dependency injection.
4+ */
5+6+import {getEnv, IStateTreeNode} from 'mobx-state-tree'
7+8+export class Environment {
9+ constructor() {}
10+11+ async setup() {}
12+}
13+14+/**
15+ * Extension to the MST models that adds the environment property.
16+ * Usage:
17+ *
18+ * .extend(withEnvironment)
19+ *
20+ */
21+export const withEnvironment = (self: IStateTreeNode) => ({
22+ views: {
23+ get environment() {
24+ return getEnv<Environment>(self)
25+ },
26+ },
27+})
+30
src/state/index.ts
···000000000000000000000000000000
···1+import {onSnapshot} from 'mobx-state-tree'
2+import {RootStoreModel, RootStore} from './models/root-store'
3+import {Environment} from './env'
4+import * as storage from './storage'
5+6+const ROOT_STATE_STORAGE_KEY = 'root'
7+8+export async function setupState() {
9+ let rootStore: RootStore
10+ let data: any
11+12+ const env = new Environment()
13+ try {
14+ data = (await storage.load(ROOT_STATE_STORAGE_KEY)) || {}
15+ rootStore = RootStoreModel.create(data, env)
16+ } catch (e) {
17+ console.error('Failed to load state from storage', e)
18+ rootStore = RootStoreModel.create({}, env)
19+ }
20+21+ // track changes & save to storage
22+ onSnapshot(rootStore, snapshot =>
23+ storage.save(ROOT_STATE_STORAGE_KEY, snapshot),
24+ )
25+26+ return rootStore
27+}
28+29+export {useStores, RootStoreModel, RootStoreProvider} from './models/root-store'
30+export type {RootStore} from './models/root-store'
+16
src/state/models/root-store.ts
···0000000000000000
···1+/**
2+ * The root store is the base of all modeled state.
3+ */
4+5+import {Instance, SnapshotOut, types} from 'mobx-state-tree'
6+import {createContext, useContext} from 'react'
7+8+export const RootStoreModel = types.model('RootStore').props({})
9+10+export interface RootStore extends Instance<typeof RootStoreModel> {}
11+export interface RootStoreSnapshot extends SnapshotOut<typeof RootStoreModel> {}
12+13+// react context & hook utilities
14+const RootStoreContext = createContext<RootStore>({} as RootStore)
15+export const RootStoreProvider = RootStoreContext.Provider
16+export const useStores = () => useContext(RootStoreContext)