FSA Actions, Reducers, Matchers and RxJS Utils This TypeScript library provides:
Factories for creating fully-typed FSA-compliant Actions. Composable reducers and Action filters. RxJS
operators for easier async Effects set-up.@ngrx/store
lazy MemoizedSelectorexport type Meta = Readonly < object > & { readonly [ key :string ] :any } ; export interface Action < P , M extends Meta = Meta > { readonly type :string ; readonly payload :P ; readonly meta :M ; readonly error :boolean ; } /ngrx
and/rxjs
libs are compatible withAngular 6
andRxJS 6
.
Basic Empty and Syncronous Actions import { actionCreatorFactory } from "rx-fsa/actions" ; const counterActionFactory = actionCreatorFactory ( "COUNTER" ) ; const resetCounterFactory = counterActionFactory ( "RESET" ) ; const resetActionAction = resetCounterFactory ( undefined ) ; const incrementCounterFactory = counterActionFactory < number > ( "INCREMENT" ) ; const incrementOneAction = incrementCounterFactory ( 1 ) ; const decrementCounterFactory = counterActionFactory < number > ( "INCREMENT" ) ; const decrementAction = ( count :number ) => decrementCounterFactory ( count ) ; interface State { readonly count ?:number ; } const saveCountFactory = counterActionFactory . async < State , void , Error > ( "SAVE" ) ; const saveCountStartedAction = saveCountFactory . started ( { count :100 } ) ; const saveCountDoneAction = saveCountFactory . done ( { result :100 , params :{ count :100 } } ) ; const saveCountFailedAction = saveCountFactory . failed ( { error :new Error ( "File not saved." ) , params :{ count :100 } } ) ; import { caseFn , Re , reducerDefaultFn } from "rx-fsa/reducers" ; const INIT_STATE :State = { count :0 } ; const resetHandler :Re < State , void > = state => INIT_STATE ; const incrementHandler :Re < State , number > = ( state , add ) => ( { count :state . count + add , } ) ; const decrementHandler :Re < State , number > = ( state , sub ) => ( { count :state . count - sub , } ) ; export const reducers = reducerDefaultFn ( INIT_STATE ) ( caseFn ( incrementCounterFactory , incrementHandler ) , caseFn ( decrementCounterFactory , decrementHandler ) , caseFn ( resetCounterFactory , resetHandler ) , ) ; The following operators are provided underrx-fsa/rxjs
:
filterConcatAsync filterExhaustAsync filterMergeAsync filterSwitchAsync filterConcat filterExhaust filterMerge filterSwitch filterActions Example with NgRx Effects:
import { filterExhaustAsync } from "rx-fsa/rxjs" ; @Effect ( ) public saveCount$ = this . action$ . pipe ( filterExhaustAsync ( saveCountFactory , params => this . httpSvc . save ( params ) ) , ) ; The above is equivalent to:
@Effect ( ) public saveCount$ = this . action$ . pipe ( filter ( saveCountFactory . started . match ) , mergeMap ( ( result :R ) => this . httpSvc . save ( params ) . pipe ( map ( result = saveCountFactory . done ( { result, params} ) ) , catchError ( error => saveCountFactory . failed ( { error, params} ) , ) , ) ; Create aMemoizedSelector
that will emit a store slice or, if unavailable, dispatch action(s) to set the store slice and then emit.
// selectors.ts import { createSelector } from "@ngrx/store" ; import { composeLazySelector , createLazySelector } from "rx-fsa/ngrx" ; const selectFeature = ( state :AppState ) => state . feature ; const selectFeatureCount = createSelector ( selectFeature , state => state . counter ) ; export const lazySelectFeatureCount = createLazySelector ( selectFeatureCount , loadFeatureAction . started ( undefined ) ) ; export const lazySelectCountPlusN = composeLazySelector ( lazySelectFeatureCount , lazySelectN ) ( ( count , n ) => count + n ) ; // app.component.ts import { lazySelectFeatureCount } from './selectors' ; @Component ( { ...} ) class MyAppComponent { count :Observable < number > ; constructor ( private store$ :Store < AppState > ) { const selectFeatureCount = lazySelectFeatureCount ( this . store$ ) ; this . count = this . store$ . pipe ( selectFeatureCount ( ) ) ; } } API Documentation is coming soon. The library is small enough to scour through in GitHub to learn more.
This library was inspired by: