@sunny-g/rx-utils

2.0.0-beta.1 • Public • Published

RxJS utils

Documentation in progress... 🐢

High-level RxJS utils built to be used with bind operator (::, proposal stage).
Use library to increase readability and decrease code size for complex reactive dependencies.

API for state helpers is built around Functional Reducer pattern.

Notes

Observable is aliased as $ for brevity.

Sample 1

derived.flags
  .sample(derived.flags.map((fs) => fs.winGame)
  .filter(identity)).map((_) => (s) => assoc("ended", "win", s))

// =>

derived.flags
  ::atTrue("winGame")
  ::setState("ended", "win")

Sample 2

$
  .combineLatest(src.navi, state2, derived.flags)
  .debounce(1)
  .map([src.navi, state2, derived.flags], gameView)

// =>

render(gameView, [src.navi, state2, derived.flags]),

Sample 3

let errors = store(seeds, $.merge(
  state.map((s) => s.user.points).skip(1).map((x) => validate(Points)).map((p) => (s) => assocPath(["user", "points"], p, s)),
  state.map((s) => s.user.bonus).skip(1).map((x) => validate(Bonus)).map((p) => (s) => assocPath(["user", "points"], p, s))
))

// =>

let errors = store(seeds, $.merge(
  state::view("user.points").skip(1).map((x) => validate(Points))::toState("user.points"),
  state::view("user.bonus").skip(1).map((x) => validate(Bonus))::toState("user.bonus")
))

Install

$ npm install babel-preset-es2016
$ npm install babel-plugin-syntax-function-bind
$ npm install babel-plugin-transform-function-bind
$ npm install rx
$ npm install ramda
$ npm install rx-utils

Add to .babelrc:

{
  "plugins": [
    "syntax-function-bind",
    "transform-function-bind"
  ],
  "presets": [
    "es2016"
  ]
}

Use

let {view} = require("rx-utils")

let userEmailStream = stateStream::view("user.email")

API

$ u type for this variable (u for "upstream") is implied and omitted for brevity.

State

store

Canonical state reducer.

scan(...) + distinctUntilChanged() + shareReplay(1)

Example
update::store(...)

history

Make observable of n last upstream values.

this + scan + distinctUntilChanged() + shareReplay(1)

Example
state::history(...)

derive

Derive a state observable from a state observable.

combineLatest(...) + distinctUntilChanged() + shareReplay(1)

Example
derive(...)

deriveN

Derive a state observable from state observables.

this + combineLatest(...) + distinctUntilChanged() + shareReplay(1)

Example
deriveN(...)

Lensing

pluck

Make an observable of fragments of upstream values.
Like native .pluck with nested path support.

Example
intent::pluck("parentNode.dataset")

pluckN

Make an observable of a fragment of upstream values.

Example
intent::pluckN(["parentNode.dataset1", "parentNode.dataset2"])

view

Make an observable of a state fragment.
pluck(...) + distinctUntilChanged() + shareReplay(1)

Example
state::view("user.email")

viewN

Make an observable of state fragments.
pluckN(...) + distinctUntilChanged() + shareReplay(1)

Example
state::viewN(["user.password", "user.passwordAgain"])

toOverState : String, (u -> (sf -> sf)) -> $ (s -> s)

Apply function to upstream value, apply resulting function to state fragment.

Example
// createUser : $ User
createUser::toOverState("users", (u) => assoc(u.id, u))
// ==
// createUser : $ User
createUser.map((u) => (s) => assocPath(["users", u.id], u, s))

toSetState : String, (sf -> sf) -> $ (s -> s)

Apply function to upstream value, replace state fragment with resulting value.

Example
// resetUsers : $ User
resetUsers::toSetState("users", (us) => map(..., us))
// ==
resetUsers.map((us) => (s) => assoc("users", map(..., us), s))

overState : String, (sf -> sf) -> $ (s -> s)

Apply function to state fragment. Upstream value does not matter.

Example
// increment : $ Boolean
increment::overState("counter", (c) => c + 1)
// ==
increment.map((_) => (s) => assoc("counter", s.counter + 1, s))

setState : String, v -> $ (s -> s)

Replace state fragment with a value. Upstream value does not matter.

Example
// reset : $ Boolean
resetForm::setState("form", seedForm)
// ==
resetForm.map((_) => (s) => assoc("form", seedForm, s))

toState : String -> $ (s -> s)

Replace state fragment with upstream value.

Example
// changeUsername : $ String
changeUsername::toState("form.username"),
// ==
changeUsername.map((v) => (s) => assocPath(["form", "username"], v, s))

Filtering & sampling

filterBy

Filter observable by another observable (true = keep).

Example
intent::filterBy(...)

rejectBy

Filter observable by another observable (true = drop).

Example
intent::rejectBy(...)

at

Pass upstream value futher if its fragment satisfies a predicate.

Example
flags::at(...)::overState(...)

atTrue

Pass upstream value futher if its fragment is true.

Example
flags::atTrue(...)::overState(...)

atFalse

Pass upstream value futher if its fragment is false.

Example
flags::atFalse(...)::overState(...)

Other

render

Apply a function over observable values in a glitch-free way.

Example
let view$ = render(
  [ state$, props.get('displayText') ],
  ({ isLoading }, displayText) => (
    <div>
      {isLoading
        ? 'Loading...'
        : displayText
      }
    </div>
  ))

Readme

Keywords

Package Sidebar

Install

npm i @sunny-g/rx-utils

Weekly Downloads

1

Version

2.0.0-beta.1

License

MIT

Last publish

Collaborators

  • sunny-g