High-level RxJS utils
npm install @sunny-g/rx-utilsDocumentation in progress... :turtle:
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
``js
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
`js
$
.combineLatest(src.navi, state2, derived.flags)
.debounce(1)
.map([src.navi, state2, derived.flags], gameView)
// =>
render(gameView, [src.navi, state2, derived.flags]),
`
#### Sample 3
`js
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")
))
`
``
$ 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:
`json`
{
"plugins": [
"syntax-function-bind",
"transform-function-bind"
],
"presets": [
"es2016"
]
}
`js
let {view} = require("rx-utils")
let userEmailStream = stateStream::view("user.email")
`
$ u type for this variable (u for "upstream") is implied and omitted for brevity.
#### store
Canonical state reducer.
scan(...) + distinctUntilChanged() + shareReplay(1)
##### Example
`js`
update::store(...)
#### history
Make observable of n last upstream values.
this + scan + distinctUntilChanged() + shareReplay(1)
##### Example
`js`
state::history(...)
#### derive
Derive a state observable from a state observable.
combineLatest(...) + distinctUntilChanged() + shareReplay(1)
##### Example
`js`
derive(...)
#### deriveN
Derive a state observable from state observables.
this + combineLatest(...) + distinctUntilChanged() + shareReplay(1)
##### Example
`js`
deriveN(...)
#### pluck
Make an observable of fragments of upstream values.
Like native .pluck with nested path support.
##### Example
`js`
intent::pluck("parentNode.dataset")
#### pluckN
Make an observable of a fragment of upstream values.
##### Example
`js`
intent::pluckN(["parentNode.dataset1", "parentNode.dataset2"])
#### view
Make an observable of a state fragment.
pluck(...) + distinctUntilChanged() + shareReplay(1)
##### Example
`js`
state::view("user.email")
#### viewN
Make an observable of state fragments.
pluckN(...) + distinctUntilChanged() + shareReplay(1)
##### Example
`js`
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
`js`
// 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
`js`
// 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
`js`
// 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
`js`
// reset : $ Boolean
resetForm::setState("form", seedForm)
// ==
resetForm.map((_) => (s) => assoc("form", seedForm, s))
#### toState : String -> $ (s -> s)
Replace state fragment with upstream value.
##### Example
`js`
// changeUsername : $ String
changeUsername::toState("form.username"),
// ==
changeUsername.map((v) => (s) => assocPath(["form", "username"], v, s))
#### filterBy
Filter observable by another observable (true = keep).
##### Example
`js`
intent::filterBy(...)
#### rejectBy
Filter observable by another observable (true = drop).
##### Example
`js`
intent::rejectBy(...)
#### at
Pass upstream value futher if its fragment satisfies a predicate.
##### Example
`js`
flags::at(...)::overState(...)
#### atTrue
Pass upstream value futher if its fragment is true.
##### Example
`js`
flags::atTrue(...)::overState(...)
#### atFalse
Pass upstream value futher if its fragment is false.
##### Example
`js`
flags::atFalse(...)::overState(...)
#### render
Apply a function over observable values in a glitch-free way.
##### Example
`js``
let view$ = render(
[ state$, props.get('displayText') ],
({ isLoading }, displayText) => (
{isLoading
? 'Loading...'
: displayText
}
))