Skip to content

Instantly share code, notes, and snippets.

@kaosat-dev
Forked from wclr/cycle-state-ramda.md
Created February 18, 2017 13:48
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 kaosat-dev/3c1521f127bdaf8b7ad7fcdc591c369a to your computer and use it in GitHub Desktop.
Save kaosat-dev/3c1521f127bdaf8b7ad7fcdc591c369a to your computer and use it in GitHub Desktop.
A way to handle state in cycle.js

A way to handle state in cycle.js

Simple state management with xstream and ramda, in more transparent fashion than onionify

import * as R from 'ramda'

// first we create factory for making special state stream 
// that will hold our stream value and will be modified with supplied streams of reducers
type StateReducer<T> = (state: T) => T
type StateStreamReduce<T> = (...reducerStreams: Stream<StateReducer<T>>[]) => void
type StateStream<T> = Stream<T> & { reduce: StateStreamReduce<T> }

const createState = <T>(initialState?: T): StateStream<T> => {	
  let reducer$ = xs.create<StateReducer<T>>();
  let state$ = <any>reducer$
    .fold<T>((state, reducer) => reducer(state), initialState!)
   
  // let's polute state$ with special method that will take streams of reducers, 
  // that will be used to modify state
  state$.reduce = (...reducersStreams: Stream<StateReducer<T>>[]) => {
    reducer$.imitate(xs.merge(...reducersStreams))
  }
  return state$
}

const Main = ({...}: Sources): Sinks => {
  // create state stream with innitial state value (optionally)
  let state$ = createState({count: 0, child: {some: 'data'}})
  
  // here is some child component that supposed to deal "child" state part.
  // Using `dropRepeats` will ensure that new value on childState$ will only  be emitted when 
  // object's value under "child" property changed (this is the case when we modify state 
  // keeping its immutability using Ramda)  
  let childState$ = state$.map(R.prop('child')).compose(dropRepeats())
  let child = Child({ state$: childState$ }								
  
  state$.reduce( 
    // lets increase state's "count" property
    xs.of(R.over(R.lensProp('count'), R.inc)),
    // Our child will aslso return `reducer$` stream that we should apply to "child" state part.
    // Using Ramda lenses we make elegantly apply child's reducer to "child" property
    child.reducer$.map(R.over(R.lensProp('child')))
  )
  
  return {
  ....
  }
}

This is actually just an idea for implementation. You may invent what ever you want on top of it. For working with other libs (rx, most) you may try to implement circular dependency for reducer$ stream with cycle-proxy

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