I'm learning NgRx and I have a basic question. I've been looking at sample projects and other answers and they are all from 2017 where the architecture was a bit different.
I'm implementing a login feature, everything so far is working fine, actions are being called, rest Api request been made, etc. My only question is: where do I redirect the user to the dashboard?
Actions:
export const loginAction = createAction(
'[Login Page] User Login',
props<{ login: string; password: string }>()
);
export const loginSuccessAction = createAction(
'[Auth] Login Complete',
props<{user: UserModel}>()
);
export const loginFailAction = createAction('[Auth] Login Fail', props<{error: any}>());
Reducers:
export interface AuthState{
isLoggedIn: boolean;
user: UserModel | null;
}
export const initialState: AuthState = {
isLoggedIn: false,
user: null
};
const _authReducer = createReducer(
initialState,
on(loginAction, (state) => ({...state, isLoggedIn: false, user: null})),
on(loginSuccessAction, (state, {user}) => ({...state, isLoggedIn: true, user: user})),
on(loginFailAction, (state) => ({ isLoggedIn: false, user: null }))
);
// tslint:disable-next-line:typedef
export function authReducer(state, action) {
return _authReducer(state, action);
}
Effects:
@Injectable()
export class AuthEffects {
constructor(
private actions$: Actions,
private authService: AuthService
) {}
@Effect()
login$ = createEffect(() =>
this.actions$.pipe(
ofType(loginAction),
exhaustMap(action =>
this.authService.login(action.login, action.password).pipe(
map(user => loginSuccessAction({user: user.redmine_user})),
catchError(error => of(loginFailAction({ error })))
)
)
)
);
}
In my component:
ngOnInit(): void
{
this.loginForm = this._formBuilder.group({
login : ['', Validators.required],
password: ['', Validators.required]
});
}
onLogin(): void{
this._store.dispatch(loginAction(this.loginForm.value));
}
ngOnDestroy(): void {
}
As I said, actions are being triggered successfully. I can see the loginSuccessAction
being called in the Redux Dev Tools. I've seen people doing the redirect inside the effect, but is that the right place to do it? If not, where should I do? Is there something like listen to actions?
If I understand correctly, you're asking where to perform redirection after a user logs in, but not in the technical sense of how to do it but in an architectural sense of where is the right place to do it.
Let's go over the options you have:
Redirect in the effect - This is your first option, redirecting in the effect before or after dispatching a success action to the reducer.
Redirecting from the service - You can also redirect after the service for example like this:
myService(): void {
return this.http.get(url).pipe(
tap(() => this.router.navigate([navigationURL]))
)
}
subscribe
, and redirect when that happens, I DO NOT recommend that approach.I think that adding subscriptions
is adding unnecessary complexity to the project, because subscriptions
have to be managed.
So what to do?
Honestly, this is up to you, both options seems valid and I wouldn't say either is a bad practice. I personally prefer to keep my effects clean and do it in the service. I feel like the service is better suited to handle side effects, and it makes it a bit cleaner also when testing, but this is my personal opinion.
The important thing to remember is, both options are valid and don't add unnecessary complexity.
There's also one small case which might apply to you, if you need that the user will be in the store
before redirecting, it might be better to put this in the effects after dispatching an actions to the reducer. If you're working with Observables it will work either way, but it might be easier to understand if they have tight relationship.