Skip to content

Instantly share code, notes, and snippets.

@JRJurman
Last active December 14, 2019 17:25
Show Gist options
  • Select an option

  • Save JRJurman/17c0201127166c821539131628ca2642 to your computer and use it in GitHub Desktop.

Select an option

Save JRJurman/17c0201127166c821539131628ca2642 to your computer and use it in GitHub Desktop.
Global Observable Hook?

Problem

I would like a single hook that exposes both global and local state. Something akin to:

const home = () => {
  const [count] = useObservable(0)
  const [globalCount] = useObservable('global-count', 0)
}

The issue is that if someone only wants to read a global variable, it might look like the following:

const home = () => {
  const [globalCount] = useObservable('global-count')
}

This is indistinguishable from an observable that is just storing a string:

const home = () => {
  const [color] = useObservable('blue')
}

Potential Solutions

Have two hooks

The current implemented solution is to have two unique hooks, useObservable and useGlobalObservable:

const home = () => {
  const [count] = useObservable(0)
  const [globalCount] = useGlobalObservable('global-count', 0)
}

Flip parameters

It would be trivial to flip the parameters such that key is the second parameter. However this means that in some cases (where we just want to read a global value), you would have to pass undefined.

const home = () => {
  const [globalCount] = useObservable(undefined, 'global-count')
}

Take in an object

We could take in an object which has a default key and a key key. At the risk of being slightly non-standard (with React's own hook interface) and potentially hard to read (depending on what the default value is). I like this option the least...

const home = () => {
  const [globalCount] = useObservable({ key: 'global-count' })
  const [color] = useObservable({ default: 'blue' })
}

Disallow primitive values

A slightly tangental issue that the interface for observable hooks is different depending on if you have a primitive data type or an object... You should only use set___ on primitives, not on objects.

const home = () => {
  const [counter, setCounter] = useObservable({ count: 0 })
  const onIncrement = () => {
    setCounter(counter.count + 1) // bad! Tram-One will throw warning
    counter.count += 1 // good! updates only things dependent on count
  }
}

A way to avoid confusion might be to only allow objects as the default value, and if there is a key, we can assume it's a global-key. Doing this will make the interface more consistent, but slightly annoying for instances where you really just want to manage a number, string, or boolean.

const home = () => {
  const globalCounter = useObservable('global-counter') // must be key
  const localCounter = useObservable({ count: 0 }) // must be local
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment