Skip to content

Instantly share code, notes, and snippets.

@mattmccray
Last active June 17, 2020 23:07
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mattmccray/2297241c9122d22af87769c5f7e46fb0 to your computer and use it in GitHub Desktop.
Save mattmccray/2297241c9122d22af87769c5f7e46fb0 to your computer and use it in GitHub Desktop.
useStreamedState
import * as React from 'react'
import { stream, scan } from 'flyd'
import merge from 'mergerino'
interface StreamedStateConfigObject<T, A> {
state: T, actions: (updater: (value: Partial<T>) => void) => A
}
type StreamedStateConfigBuilder<T, A> = () => StreamedStateConfigObject<T, A>
type StreamedStateConfig<T, A> = StreamedStateConfigObject<T, A> | StreamedStateConfigBuilder<T, A>
export function useStreamedState<T, A>(def: StreamedStateConfig<T, A>): [T, A] {
const container = React.useRef(null)
const config = React.useMemo(() => (typeof def === 'function' ? def() : def), [])
const [state, setState] = React.useState(config.state)
if (container.current === null) {
const states = stream(config.state)
const changes = scan(merge as any, config.state, states)
const actions = config.actions(states)
changes.map(state => { setState(state) })
container.current = { states, changes, actions }
}
return [state, container.current.actions]
}
export default useStreamedState
@mattmccray
Copy link
Author

TODO: Figure out how to properly type mergerino's updater function support.

const TestCounter = () => {
  const [{ count }, actions] = useStreamedState(() => ({
    state: {
      count: 0,
    },
    actions: update => ({
      increment() {
        update({ count: (c) => c + 1 }) // This should be allowed by Typescript... somehow
      },
      decrement() {
        update({ count: (c) => c - 1 })
      }
    })
  }))

  return (
    <div>
      <button onClick={actions.decrement}>-</button>
      <span>{count}</span>
      <button onClick={actions.increment}>+</button>
    </div>
  )
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment