Reputation: 319
I start learn to work with NgRx library and after I learn the basic of how to save state with dispatch and get the state with the store, I move to effect and try to understand and implement it but its not fire.
user.model
export interface User {
userID: number;
id: number;
title: string;
completed: boolean;
}
user.action
import { Action } from '@ngrx/store';
import { User } from '../models/user.model';
export const LOAD_USER = '[USER] Load';
export class LoadUser implements Action {
readonly type = LOAD_USER;
constructor(public payload: User) {}
}
export type Action = LoadUser;
user.reducer
import { User } from '../models/user.model';
import * as UserAction from '../actions/user.actions';
const initialState: User = {
userID: null,
id: null,
title: null,
completed: null
};
export function userReducer(state: User = initialState, action: UserAction.Action) {
switch (action.type) {
case UserAction.LOAD_USER:
return action.payload;
default:
return state;
}
}
app.state
import { Comment } from './models/comment.model';
import { User } from './models/user.model';
export interface AppState {
readonly comment: Comment[];
readonly counter: number;
readonly user: User[];
}
app.module
imports: [
BrowserModule,
HttpClientModule,
AppRoutingModule,
FormsModule,
ReactiveFormsModule,
StoreModule.forRoot({
comment: commentReducer,
counter: counterReducer,
user: userReducer
}),
EffectsModule.forRoot([UserEffect]),
StoreDevtoolsModule.instrument({
maxAge: 25, // Retains last 25 states
}),
],
user.efect
import { Injectable } from '@angular/core';
import { Actions, ofType, createEffect } from '@ngrx/effects';
import { EMPTY } from 'rxjs';
import { map, mergeMap, catchError } from 'rxjs/operators';
import { UserService } from '../core/services/user.service';
import * as UserAction from '../actions/user.actions';
@Injectable()
export class UserEffect {
$loadUser = createEffect(() => this.actions$.pipe(
ofType(UserAction.LOAD_USER),
mergeMap(() => this.userService.getUsers().pipe(
map((user) => new UserAction.LoadUser({userID: user[0].userID, id: user[0].id, title: user[0].title, completed: user[0].completed}))
)),
catchError(() => EMPTY)
));
constructor(
private actions$: Actions,
private userService: UserService
) {
}
}
user.service:
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
@Injectable({
providedIn: 'root'
})
export class UserService {
constructor(private http: HttpClient) { }
getUsers() {
return this.http.get('https://jsonplaceholder.typicode.com/todos/1');
}
}
I look in chrome dev-tool and it seems that the event not fire. What the problem? thanks
When i try to call the action/dispatch from component But isn't that job done with the effect? with parameter i need to input ?
ngOnInit() {
this.store.dispatch(new UserActions.LoadUser({ userID: null, id: null, title: null, completed: null }))
}
Upvotes: 0
Views: 628
Reputation: 6637
You would need two different actions, one LOAD_USER
to trigger the load and second e.g. USER_LOADED
to carry the user information from service and save it in the reducer.
This is how your actions would look like:
export const LOAD_USER = '[USER] Load';
export const USER_LOADED = '[USER] Loaded';
export class LoadUser implements Action {
readonly type = LOAD_USER; // no payload => no constructor needed
}
export class UserLoaded implements Action {
readonly type = USER_LOADED;
constructor(public payload: User) {}
}
your reducer reacts to both actions:
export function userReducer(state: User = initialState, action: UserAction.Action) {
switch (action.type) {
case UserAction.LOAD_USER:
return initialState; // reset user to default value while loading
case UserAction.USER_LOADED:
return action.payload;
default:
return state;
}
}
and your effect slightly different:
$loadUser = createEffect(() => this.actions$.pipe(
ofType(UserAction.LOAD_USER),
mergeMap(() => this.userService.getUsers().pipe(
map(user => new UserAction.UserLoaded(user[0]))
)),
catchError(() => EMPTY)
));
The way your effect was written can cause memory leak actually, while you are creating endless loop - when LoadUser is fired, you fetch user and fire LoadUser, which triggers the effect again...
Upvotes: 0