Skip to content

Commit

Permalink
Consolidate store hooks
Browse files Browse the repository at this point in the history
Replace the three store hooks with a single `useHydratedStore` hook. Use synchronous storage.
  • Loading branch information
eatyourgreens committed Mar 21, 2022
1 parent 7a7788a commit c9fac2e
Show file tree
Hide file tree
Showing 10 changed files with 56 additions and 168 deletions.

This file was deleted.

This file was deleted.

1 change: 0 additions & 1 deletion packages/lib-classifier/src/helpers/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import * as featureDetection from './featureDetection'
export { default as asyncSessionStorage } from './asyncSessionStorage'
export { default as createLocationCounts } from './createLocationCounts'
export { featureDetection }
export { default as findLocationsByMediaType } from './findLocationsByMediaType'
Expand Down
29 changes: 2 additions & 27 deletions packages/lib-classifier/src/hooks/Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,37 +4,12 @@

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 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 classifierStore = useHydratedStore({ authClient, client }, enableStorage = false, storageKey)
```

## useSavedSnapshot

Asynchronously load a store snapshot from session storage.

```js
const initialState = useSavedSnapshot(enableStorage, storageKey)
```

## useSessionStorage

Wrap a store in an [`onSnapshot`](https://mobx-state-tree.js.org/API/#onsnapshot) listener, which writes snapshots asynchronously to session storage. Returns the wrapped store.
Returns the new store when hydration is complete. Snapshots are stored in session storage, so that they don't persist across tabs or windows.

```js
const persistedStore = useSessionStorage(cachePanoptesData, classifierStore, storageKey)
const classifierStore = useHydratedStore({ authClient, client }, cachePanoptesData = false, storageKey)
```

## useStore

Create a `mobx-state-tree` store, using the Panoptes API clients and an optional snapshot. Adapted from [the NextJS example](https://github.com/vercel/next.js/blob/5201cdbaeaa72b54badc8f929ddc73c09f414dc4/examples/with-mobx-state-tree/store.js#L49-L52), which is also used in `app-project`. `initialState` must be a valid store snapshot.

```js
const classifierStore = useStore({ authClient, client, initialState })
````
## useWorkflowSnapshot

A wrapper for [`useSWR`](https://swr.vercel.app/), which fetches a workflow by ID, using the default SWR options. The workflow will refresh on visibility change (eg. waking from sleep), or when the classifier receives focus.
Expand Down
3 changes: 0 additions & 3 deletions packages/lib-classifier/src/hooks/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,2 @@
export { default as useHydratedStore } from './useHydratedStore'
export { default as useSavedSnapshot } from './useSavedSnapshot'
export { default as useSessionStorage } from './useSessionStorage'
export { default as useStore } from './useStore'
export { default as useWorkflowSnapshot } from './useWorkflowSnapshot'
55 changes: 48 additions & 7 deletions packages/lib-classifier/src/hooks/useHydratedStore.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,51 @@
import { useSavedSnapshot, useSessionStorage, useStore } from './'
import makeInspectable from 'mobx-devtools-mst'
import { addDisposer, onSnapshot } from 'mobx-state-tree'
import { useMemo } from 'react'

import RootStore from '@store'

function loadSnapshot(storageKey, storage) {
const data = storage.getItem(storageKey)
return JSON.parse(data) || {}
}

function persist(storageKey, _store, storage) {
function _saveSnapshot(snapshot) {
const data = JSON.stringify(snapshot)
storage.setItem(storageKey, data)
}
const snapshotDisposer = onSnapshot(_store, _saveSnapshot)
return addDisposer(_store, snapshotDisposer)
}

let store = null

function initStore({ authClient, cachePanoptesData, client, storageKey }) {
if (store === null) {
let initialState = {}

if (cachePanoptesData) {
initialState = loadSnapshot(storageKey, window.sessionStorage)
}

store = RootStore.create(initialState, {
authClient,
client
})

if (cachePanoptesData) {
persist(storageKey, store, window.sessionStorage)
}
makeInspectable(store)
}
return store
}

export function cleanStore() {
store = null
}

export default function useHydratedStore({ authClient, client }, cachePanoptesData = false, storageKey) {
// Asynchronously load a store snapshot from an external source.
const initialState = useSavedSnapshot(cachePanoptesData, storageKey)
// Create a new store from the initialState snapshot.
const classifierStore = useStore({ authClient, client, initialState })
// Write store snapshots to session storage.
return useSessionStorage(cachePanoptesData, classifierStore, storageKey)
const _store = useMemo(() => initStore({ authClient, cachePanoptesData, client, storageKey }), [authClient, cachePanoptesData, client, storageKey])
return _store
}
16 changes: 6 additions & 10 deletions packages/lib-classifier/src/hooks/useHydratedStore.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { renderHook } from '@testing-library/react-hooks/pure'

import mockStore from '@test/mockStore'
import RootStore from '@store/RootStore'
import { cleanStore } from './useStore'
import { cleanStore } from './useHydratedStore'
import { useHydratedStore } from '.'

describe('Hooks > useHydratedStore', function () {
Expand Down Expand Up @@ -52,11 +52,10 @@ describe('Hooks > useHydratedStore', function () {
describe('with session storage enabled', function () {
let store

beforeEach(async function () {
beforeEach(function () {
const expectedStore = mockStore()
const { authClient, client } = expectedStore
const { result, waitForNextUpdate } = renderHook(() => useHydratedStore({ authClient, client }, true, 'test-key'))
await waitForNextUpdate()
const { result } = renderHook(() => useHydratedStore({ authClient, client }, true, 'test-key'))
store = result.current
const mockSnapshot = getSnapshot(expectedStore)
applySnapshot(store.projects, mockSnapshot.projects)
Expand All @@ -77,17 +76,14 @@ describe('Hooks > useHydratedStore', function () {
let store
let mockSnapshot

beforeEach(async function () {
beforeEach(function () {
const expectedStore = mockStore()
mockSnapshot = getSnapshot(expectedStore)
window.sessionStorage.setItem('test-key', JSON.stringify(mockSnapshot))

const { authClient, client } = expectedStore
const { result, waitFor } = renderHook(() => useHydratedStore({ authClient, client }, true, 'test-key'))
await waitFor(() => {
store = result.current
return !!store?.projects
})
const { result } = renderHook(() => useHydratedStore({ authClient, client }, true, 'test-key'))
store = result.current
})

afterEach(function () {
Expand Down
39 changes: 0 additions & 39 deletions packages/lib-classifier/src/hooks/useSavedSnapshot.js

This file was deleted.

25 changes: 0 additions & 25 deletions packages/lib-classifier/src/hooks/useSessionStorage.js

This file was deleted.

30 changes: 0 additions & 30 deletions packages/lib-classifier/src/hooks/useStore.js

This file was deleted.

0 comments on commit c9fac2e

Please sign in to comment.