React stack based on rxjs
- Only for TypeScript (checking type in coding over in runtime)
- No any propTypes for runtime checking
- Only support react and it's version must be 16.8+
react hooks
is so cool
This is a redux-like library, and:
-
Declare class
Actor
, implementsRedux Action
:group: string
- classifying actions
name: string
- action name
stage?: AsyncStage
- mark async stage
STARTED
,DONE
,FAILED
- mark async stage
get type(): string
- computed by
group
,name
andstage
, evenopts
- to implement Redux Action for compatible with the Redux Middleware
- computed by
arg
: taking major dataopts
: taking metadataeffect?: (prevState: TState, actor: Actor) => TState
- same as Redux Reducer: inputs
prevState
andactor
, outputnextState
- avoiding
rootReducer
to make dynamics(import
) happy, - avoiding nested state, could use
effectOn
to scope effect node
- same as Redux Reducer: inputs
-
Declare
Store
witch extendsBehaviorSubject
, implementsRedux Store
:getState: () => TState
- same as
ReduxStore.getState
or usegetValue
orvalue
which extendsBehaviorSubject
instead
- same as
dispatch: (actor: Actor) => void
- similar as
ReduxStore.dispath
, but limit to dispatchActor
only
- similar as
subscribe: (nextState: TState) => Subscription
- similar as
ReduxStore.subscribe
, but return aSubscription
and as an observer
- similar as
actor$: Subject<Actor>
- A subject Actor
epicOn: (TEpic<TState>) => Subscription
:TEpic<TState> = (actor$: Observable<Actor>, state$: Store<TState>): Observable<Actor>
- inspired by redux-observable
- handling side effects
applyMiddleware: (...middlewares: IMiddleware<TRoot>[])=> void
- same as
ReduxUtils.applyMiddleware
- same as
- drop
replaceReducer
- there are no more rootReducer, and no need
ReduxUtils.combineReducers
too.
- there are no more rootReducer, and no need
import { Store, Actor, Volume, renderOn } from "@reactorx/core"
import { filter, map } from "rxjs/operators"
const testActor = Actor.of("test");
const ping = testActor.named<{ step?: number }, { o: string }>("ping").effectOn("ping", (state: any = 0, actor) => {
return state + (actor.arg.step || 1);
});
const pong = testActor.named("pong").effectOn("pong", (state: any = 0) => {
return state + 1;
});
const so$ = Store.create({ ping: 0, pong: 0 });
so$.applyMiddleware(() => (next) => (actor) => next(actor));
const pingStates: number[] = [];
const pongStates: number[] = [];
Volume.from(so$, (state) => state["ping"]).subscribe((nextState) => {
pingStates.push(nextState);
});
Volume.from(so$, (state) => state["pong"]).subscribe((nextState) => {
pongStates.push(nextState);
});
renderOn(so$, () => {
return null;
});
so$.epicOn((actor$) => {
return actor$.pipe(
filter(ping.is),
map(() => {
return pong.with({});
}),
);
});
for (let i = 0; i < 5; i++) {
ping.with({}).invoke(so$);
expect(so$.getState()).toEqual({
ping: 1 + i,
pong: 1 + i,
});
}
expect(pingStates).toEqual([0, 1, 2, 3, 4, 5]);
expect(pongStates).toEqual([0, 1, 2, 3, 4, 5]);
Core rules copy form react-router without compatibility for old version. and provide:
useRouter
insteadwithRouter
ReactorxRouter
routerActors
for navigate through dispatching actor- syncing
history.location
toState["$$location"]
base on axios, provide:
createRequestActor<TArg, TRespData, TRespErr>(name: string, (arg: TArg) => IRequestOpts: RequestActor<TArg, TRespData, TRespErr>
- request actor builder
- epics for handles
RequestActor
createCombineDuplicatedRequestEpic
to unique requestcreateRequestEpic
to send all request and resolve or reject matched response
see testings
similar as redux-form