Currently, I want to use NgRx on my project, and I have a question connected with getting data from the server.
For example, I have this code.
in component
// import ....
export class ToDoComponent implements OnInit {
todo$: Observable<ToDoState>;
ToDoSubscription: Subscription;
ToDoList: ToDo[] = [];
constructor(private store: Store<{ todos: ToDoState }>) {
this.todo$ = store.pipe(select('todos'));
}
ngOnInit() {
this.ToDoSubscription = this.todo$
.pipe(
map(x => {
this.ToDoList = x.ToDos;
this.todoError = x.ToDoError;
})
)
.subscribe();
this.store.dispatch(ToDoActions.BeginGetToDoAction());
}
}
and this one
in Effects
// import ....
@Injectable()
export class ToDoEffects {
constructor(private http: HttpClient, private action$: Actions) {}
private ApiURL: string = 'https://localhost:44308/api/ToDo';
GetToDos$: Observable<Action> = createEffect(() =>
this.action$.pipe(
ofType(ToDoActions.BeginGetToDoAction),
mergeMap(action =>
this.http.get(this.ApiURL).pipe(
map((data: ToDo[]) => {
return ToDoActions.SuccessGetToDoAction({ payload: data });
}),
catchError((error: Error) => {
return of(ToDoActions.ErrorToDoAction(error));
})
)
)
)
);
}
Does it mean that I will send a request to the server every time when the user navigates to the ToDoComponent
component?
If yes, how can I configure my effect to send a request only once?
Or what is the best way for this case?
Any help will be appreciated.
Thanks!
Yes, everytime you navigate to the component it will fetch the todo.
This is because of the dispatch line,
this.store.dispatch(ToDoActions.BeginGetToDoAction());
You can check if it's already present in the store as seen in Start using ngrx/effects for this
@Effect()
getOrder = this.actions.pipe(
ofType<GetOrder>(ActionTypes.GetOrder),
withLatestFrom(action =>
of(action).pipe(
this.store.pipe(select(getOrders))
)
),
filter(([{payload}, orders]) => !!orders[payload.orderId])
mergeMap([{payload}] => {
...
})
)
Or you can just put a take(1)
in your effect:
GetToDos$: Observable<Action> = createEffect(() =>
this.action$.pipe(
ofType(ToDoActions.BeginGetToDoAction),
mergeMap(action =>
this.http.get(this.ApiURL).pipe(
map((data: ToDo[]) => {
return ToDoActions.SuccessGetToDoAction({ payload: data });
}),
catchError((error: Error) => {
return of(ToDoActions.ErrorToDoAction(error));
})
)
),
take(1)
)
);
here is the stackblitz example. https://stackblitz.com/edit/angular-d6jctm