useMeteorState - useState with data persistence

I wrote a cool hook! It’s a small wrapper around useState which adds support for Meteor’s Reload package for data persistence, so that your data remains after refreshes during development and hot code push in production.

import { Meteor } from 'meteor/meteor'
import { Reload } from 'meteor/reload'
import { useState, useMemo, useEffect, SetStateAction, Dispatch } from 'react'

interface IHash {
  [key: string] : any
}

if (Meteor.isClient) {
  var toMigrate: IHash = {}
  var migrated: IHash = Reload._migrationData('use-meteor-state') || {}

  Reload._onMigrate('use-meteor-state', () => {
    return [true, toMigrate]
  })
}

interface IUseMeteorState {
  <S>(initialValue: S | (() => S), name: string): [S, Dispatch<SetStateAction<S>>]
}

const useMeteorState: IUseMeteorState = (initialValue, name) => {
  // When running in concurrent mode, this may run multiple times ...
  useMemo(() => {
    if (Meteor.isClient && migrated[name]) {
      initialValue = migrated[name]
    }
  }, [name])

  useEffect(() => {
    // ... so cleanup happens only after the render is committed
    if (migrated[name]) {
      // move to toMigrate for next refresh
      toMigrate[name] = migrated[name]
      // remove migrated so lifecycle can do its thing
      delete migrated[name]
    }
    return () => {
      // Remove migration on unmount
      if (toMigrate[name]) {
        delete toMigrate[name]
      }
    }
  }, [name])

  const [value, setValue] = useState(initialValue)

  return [value, (value) => {
    toMigrate[name] = value
    setValue(value)
  }]
}

export default useMeteorState

6 Likes

Will try it out ASAP. I’m wondering if this isn’t something that should be part of the official Metoer React package.

1 Like

I have this and a bunch of other hooks (mentioned on various forum posts) that I think should probably be part of an official package (or maybe set of packages). One important aspect of some of those is to move to the useMutableSource model for data retrieval from computations. That isn’t quite ready to share though.

3 Likes

One scenario I’m using it for is a search field and search results. I was trying to style up the search results, and every time I saved a file I’d have to rerun the search. Now each are stored using useMeteorState - the search field and the result set. So they persist between refreshes during development.