Skip to content

Commit

Permalink
Refactor useHydratedStore hook. Remove mst-persist
Browse files Browse the repository at this point in the history
- consolidate `useStore` and `useHydratedStore`, so that `useHydratedStore` calls `useStore` to create the new store.
- add a `persist` helper to manage store snapshots.
- remove `mst-persist`.
  • Loading branch information
eatyourgreens committed Mar 3, 2022
1 parent cb523a0 commit 735c2bb
Show file tree
Hide file tree
Showing 9 changed files with 54 additions and 32 deletions.
1 change: 0 additions & 1 deletion packages/lib-classifier/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@
"i18next": "~21.6.3",
"lodash": "~4.17.11",
"mobx-utils": "~6.0.4",
"mst-persist": "~0.1.3",
"react-i18next": "~11.15.1",
"react-player": "~2.9.0",
"react-resize-detector": "~7.0.0",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import {
tutorials as tutorialsClient
} from '@zooniverse/panoptes-js'

import { useHydratedStore, useStore, useWorkflowSnapshot } from './hooks'
import { useHydratedStore, useWorkflowSnapshot } from './hooks'
import { unregisterWorkers } from '../../workers'
import Classifier from './Classifier'

Expand Down Expand Up @@ -61,15 +61,11 @@ export default function ClassifierContainer({
workflowID
}) {

const classifierStore = useStore({
authClient,
client,
initialState: {}
})
const storeOptions = { authClient, client }

const workflowSnapshot = useWorkflowSnapshot(workflowID)

const loaded = useHydratedStore(classifierStore, cachePanoptesData, `fem-classifier-${project.id}`)
const { classifierStore, loaded } = useHydratedStore(storeOptions, cachePanoptesData, `fem-classifier-${project.id}`)

useEffect(function onLoad() {
const { classifications, subjects, workflows } = classifierStore
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@

## useHydratedStore

Hydrate a `mobx-state-tree` store from a stored [snapshot](https://mobx-state-tree.js.org/concepts/snapshots). Wraps the store in [`mst-persist`](https://github.com/agilgur5/mst-persist), which runs `applySnapshot(store, snapshot)` to hydrate the store, and adds an `onSnapshot` handler to keep the stored snapshot updated when the store changes.
Create a `mobx-state-tree` store from an optional stored [snapshot](https://mobx-state-tree.js.org/concepts/snapshots). Adds an `onSnapshot` handler to keep the stored snapshot updated when the store changes.

Runs asynchronously and returns `true` when hydration is complete. Snapshots are stored in session storage, so that they don't persist across tabs or windows.
Runs asynchronously and returns the new store when hydration is complete. Snapshots are stored in session storage, so that they don't persist across tabs or windows.

Uses the `useStore` hook, under the hood, to create a new store from a saved snapshot and the API clients.

```js
const loaded = useHydratedStore(store, enableStorage = false, storageKey)
const { classifierStore, loaded } = useHydratedStore({ authClient, client }, enableStorage = false, storageKey)
```

## useStore
Expand Down
Original file line number Diff line number Diff line change
@@ -1,33 +1,53 @@
import { persist } from 'mst-persist'
import { useEffect, useState } from 'react'

import { asyncSessionStorage } from '@helpers'
import { asyncSessionStorage, persist } from '@helpers'
import { useStore } from './'

async function hydrateStore(storageKey, classifierStore) {
async function hydrateStore(storageKey) {
let snapshot = {}
try {
await persist(storageKey, classifierStore, {
storage: asyncSessionStorage,
whitelist: ['fieldGuide', 'projects', 'subjects', 'subjectSets', 'tutorials', 'workflows', 'workflowSteps']
})
console.log('store hydrated from local storage')
snapshot = await loadSnapshot(storageKey, asyncSessionStorage)
console.log('store loaded from local storage')
} catch (error) {
console.log('store snapshot error.')
console.error(error)
}
return snapshot
}

export default function useHydratedStore(classifierStore, cachePanoptesData = false, storageKey) {
async function loadSnapshot(storageKey, storage) {
const data = await storage.getItem(storageKey)
const snapshot = JSON.parse(data)
return snapshot
}

export default function useHydratedStore({ authClient, client }, cachePanoptesData = false, storageKey) {
const [initialState, setInitialState] = useState(null)
const [loaded, setLoaded] = useState(false)

async function onMount() {
if (cachePanoptesData) {
await hydrateStore(storageKey, classifierStore)
const classifierStore = useStore({ authClient, client, initialState })

async function onStoreCreated() {
if (!loaded && classifierStore && cachePanoptesData) {
await persist(storageKey, classifierStore, { storage: asyncSessionStorage })
}
setLoaded(true)
}

useEffect(() => {
onMount()
onStoreCreated()
}, [cachePanoptesData, classifierStore, loaded])

async function getInitialState() {
let _initialState = {}
if (cachePanoptesData) {
_initialState = await hydrateStore(storageKey)
}
setInitialState(_initialState)
}

useEffect(() => {
getInitialState()
}, [])
return loaded

return { classifierStore, loaded }
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import RootStore from '@store'
let store

function initStore({ authClient, client, initialState }) {
if (!store) {
if (!store && initialState) {
store = RootStore.create(initialState, {
authClient,
client
Expand Down
1 change: 1 addition & 0 deletions packages/lib-classifier/src/helpers/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export { featureDetection }
export { default as findLocationsByMediaType } from './findLocationsByMediaType'
export { default as formatTimeStamp } from './formatTimeStamp'
export { default as layouts } from './layouts'
export { default as persist } from './persist'
export { default as shownMarks } from './shownMarks'
export { default as subjectsSeenThisSession } from './subjectsSeenThisSession'
export { default as subjectViewers } from './subjectViewers'
Expand Down
1 change: 1 addition & 0 deletions packages/lib-classifier/src/helpers/persist/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from './persist'
8 changes: 8 additions & 0 deletions packages/lib-classifier/src/helpers/persist/persist.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { addDisposer, applySnapshot, onSnapshot } from 'mobx-state-tree'

export default async function persist(storageKey, store, { storage }) {
addDisposer(store, onSnapshot(store, snapshot => {
const data = JSON.stringify(snapshot)
storage.setItem(storageKey, data)
}))
}
5 changes: 0 additions & 5 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -12037,11 +12037,6 @@ mst-middlewares@~5.1.0:
resolved "https://registry.yarnpkg.com/mst-middlewares/-/mst-middlewares-5.1.3.tgz#059a2cf4e44cdb44ae92eb4a4e8ce47f6c117c66"
integrity sha512-zVPxLO6kQFMTU0S7xYoyiSml8nUP5Ekto3CY4Ra7cGwbuLOwIDBgCyNIEEtLpq95KFbhAEl9oIchg4RW13iCZg==

mst-persist@~0.1.3:
version "0.1.3"
resolved "https://registry.yarnpkg.com/mst-persist/-/mst-persist-0.1.3.tgz#ac7203f3ab36085106c4293d4a9cd67dd5613708"
integrity sha512-G2IzmTvi2E8zOTTCiMENkli+KmANhpPNlkguOEJp0dioqfdETDQjLO6QKy5hXhDTRIQhu48IlDJeNdyeZ8NIaw==

multicast-dns-service-types@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz#899f11d9686e5e05cb91b35d5f0e63b773cfc901"
Expand Down

0 comments on commit 735c2bb

Please sign in to comment.