-
Notifications
You must be signed in to change notification settings - Fork 86
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Register epics in Application #40
Comments
Hi! Using rxjs 6+, Angular 6+ and Angular-redux 9+ I'm using this aproach: In the same class where epics are declared, declare an function returning an array of epics: public createEpics(): Epic<Action, Action, any, any>[] {
return [
this.viewOrgEpic(),
this.searchEpic(),
.....
];
}
private viewOrgEpic(): Epic<OrganisationAPIViewAction, OrganisationAPIViewAction, IOrganisationState, any> {
return (action$) => action$
.ofType(OrganisationAPIActions.VIEW_ORGANISATION)
.pipe(
switchMap((action: OrganisationAPIViewAction) => this.service.get(action.meta.id)
.pipe(
map((item: IOrganisationItem) => this.actions.viewByIdSuccess(action.meta.id, item)),
startWith(this.actions.viewStarted(action.meta.id))
)),
catchError(err => of(this.actions.viewFailed(err))),
);
}
........ Split up epics in several classes reflecting the architecture of app. Collect all epics in an RootEpic class: @Injectable()
export class RootEpics {
constructor(private organisationEpics: OrganisationAPIEpics, private authEpics: AuthEpics) {
}
public createEpics(): Epic<Action, Action, any, any>[] {
return this.organisationEpics.createEpics()
.concat(this.authEpics.createEpics())
......
}
} Define an rootReducer to assign different reducers to parts in the store: export const rootReducer = composeReducers(
defaultFormReducer(),
combineReducers<IAppState, Action>({
organisation: combineReducers<IOrganisationState, Action>({
view: organisationViewReducer,
....
}),
....
auth: authReducer,
router: routerReducer
})
); StoreModule is using epics and reducers in this way: const middleware = createEpicMiddleware();
store.configureStore(
rootReducer,
INITIAL_STATE,
[createLogger(), middleware],
isDevMode() && devTools.isEnabled() ? [devTools.enhancer()] : []
);
for (const epic of this.rootEpics.createEpics()) {
middleware.run(epic);
} Not sure if this is the best/right way of doing it, but it works for me. Hope it helps at least. |
@joese, FABULOUS !!! |
Above code helped me to change root epic and store configure, but i am facing one more issue. Currently i am working on migration from angular 5 to 6. While updating to redux 4 i am getting error as store.getState() is not a funtion
|
If you are upgrading, you will then encounter that Epic interface has changed to: Epic<Input extends Action = any, Output extends Input = Input, State = any, Dependencies = any> getState is not a function, you should use the .value instead. employeeValues_Epic: Epic<FSAction, FSAction, IAppState, any> = (action$, state$) => action$
.ofType(APP_Actions.ActionTypes.APP_EMPLOYEE_VALUES).pipe(
switchMap(data =>
someAction(state$.value.source1))); An epic should return an action, not a value. A reducer should pick up the action and change state accordingly. |
@joese Thank you very much. It helped me in solving my issue. Could you please give me reference documents for such epic middleware with rxjs to understand more |
|
When an Action is triggered that is declared to be caught in an Epic, that epic will be executed.
Epic is generic:
createMiddleware is returning an object of type NgRedux configureStore accepts an argument named middleware. You should pass the previously created middleware-object. This implementation for AppReduxModule should work: @NgModule({
imports: [
NgReduxModule,
NgReduxRouterModule.forRoot()
],
providers: [
NgReduxRouter,
UserEpics
]
})
export class AppReduxModule {
constructor(
private readonly ngRedux: NgRedux<MyStateType>,
private readonly devTools: DevToolsExtension,
private readonly ngReduxRouter: NgReduxRoute
private readonly userEpics: UserEpics
) {
const epicMiddleware = createEpicMiddleware();
const middlewares = [
reduxActionClassMiddleware,
epicMiddleware
];
if (!environment.production) {
middlewares.push(createLogger());
}
const epics = [].concat(
this.userEpics.getEpics(),
// Add other epics here
);
// Tell @angular-redux/store about our rootReducer and our initial state.
// It will use this to create a redux store for us and wire up all the
// events.
ngRedux.configureStore(
composeReducers(defaultFormReducer(), appReducer),
INITIAL_STATE,
middlewares,
isDevMode() && devTools.isEnabled() ? [composeWithDevTools()] : []
);
for (const epic of epics) {
epicMiddleware.run(epic);
}
if (ngReduxRouter) {
ngReduxRouter.initialize();
}
}
} Definition of UserEpics: @Injectable()
export class UserEpics {
constructor(private backend: BackendService,
private router: Router,
private redux: NgRedux<MyStateType>) {
}
getEpics = () => [].concat(
this.loginUserName,
this.catchLoginError,
)
loginUserName = ($action: ActionsObservable<LoginUsernameAction>) => {
return $action.ofType(LoginUsernameAction.actionName)
.pipe(
mergeMap((action: LoginUsernameAction) =>
this.backend.login(action.payload.username, action.payload.password)
.pipe(
mergeMap((userInfo: UserData) => concat(
of(new SetUserAction(userInfo)),
of(new LoggedInAction())
)
),
catchError((err) => of(new LoginErrorAction()))
)),
catchError((err) => of(new LoginErrorAction()))
);
}
catchLoginError = ($action: ActionsObservable<LoginErrorAction>) => {
return $action.ofType(LoginErrorAction.actionName)
.pipe(
mergeMap((action: LoginErrorAction) => of(new UserError({label: 'Login failed', message: 'Provided credentials is not valid.'})))
);
}
} |
Hi,
you wrote a Tutorial on how to register epics in a application but it seems not to work anymore.
I tried to reproduce the example and it starts with this error:

ActionObservable needs an argument T.
How can i use and register epics in my app.module? Especially with more then one epic.
Is this approach up-to-date in Version 9+?
Regards
rubiktubik
The text was updated successfully, but these errors were encountered: