[Angular] NgRx/effect, why to use it?

本文介绍了一个Angular应用程序中如何改进状态管理的方式,通过移除服务并利用ngrx库来处理数据加载和状态更新,实现更简洁高效的组件设计。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

See the current implementaion of code, we have a smart component, and inside the smart component we are using both 'serivce' and 'store'.

 

In the large application, what we really want is one service to handle the application state instead of two or more. And also we need response to the user action to get new data, all the requirements actaully can be handled by 'Store'. 

 

import {Component, OnInit} from '@angular/core';
import {Store} from '@ngrx/store';
import {ThreadsService} from "../services/threads.service";
import {AppState} from "../store/application-state";
import {AllUserData} from "../../../shared/to/all-user-data";
import {LoadUserThreadsAction} from "../store/actions";
import {Observable} from "rxjs";
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/skip';
import {values, keys, last} from 'ramda';
import {Thread} from "../../../shared/model/thread.interface";
import {ThreadSummary} from "./model/threadSummary.interface";


@Component({
  selector: 'thread-section',
  templateUrl: './thread-section.component.html',
  styleUrls: ['./thread-section.component.css']
})
export class ThreadSectionComponent implements OnInit {

  userName$: Observable<string>;
  counterOfUnreadMessages$: Observable<number>;
  threadSummary$: Observable<ThreadSummary[]>;

  constructor(private store: Store<AppState>,
              private threadsService: ThreadsService) {

    this.userName$ = store.select(this.userNameSelector);

    this.counterOfUnreadMessages$ = store.select(this.unreadMessageCounterSelector);

    this.threadSummary$ = store.select(this.mapStateToThreadSummarySelector.bind(this))
  }

  mapStateToThreadSummarySelector(state: AppState): ThreadSummary[] {
    const threads = values<Thread>(state.storeData.threads);
    return threads.map((thread) => this.mapThreadToThreadSummary(thread, state));
  }

  mapThreadToThreadSummary(thread: Thread, state: AppState): ThreadSummary {
    const names: string = keys(thread.participants)
      .map(participantId => state.storeData.participants[participantId].name)
      .join(', ');
    const lastMessageId: number = last(thread.messageIds);
    const lastMessage = state.storeData.messages[lastMessageId];
    return {
      id: thread.id,
      participants: names,
      lastMessage: lastMessage.text,
      timestamp: lastMessage.timestamp
    };
  }

  userNameSelector(state: AppState): string {
    const currentUserId = state.uiState.userId;
    const currentParticipant = state.storeData.participants[currentUserId];

    if (!currentParticipant) {
      return "";
    }

    return currentParticipant.name;
  }

  unreadMessageCounterSelector(state: AppState): number {
    const currentUserId: number = state.uiState.userId;

    if (!currentUserId) {
      return 0;
    }

    return values<Thread>(state.storeData.threads)
      .reduce(
        (acc: number, thread) => acc + (thread.participants[currentUserId] || 0)
        , 0);
  }

  ngOnInit() {

    this.threadsService.loadUserThreads()
      .subscribe((allUserData: AllUserData) => {
        this.store.dispatch(new LoadUserThreadsAction(allUserData))
      });
  }

}

 

So what we want to do to improve the code is to "remove the service from the component, let it handle by ngrx/effect" lib.

 

Here instead we call the service to get data, we will dispatch an action call 'LoadUserTreadsAction', and inside this action, will have side effect either "UserTreadsLoadSuccess" or "UserTreadsLoadError".

 

Create a effect service:

import {Injectable} from '@angular/core';
import {Action} from '@ngrx/store';
import {Actions, Effect} from "@ngrx/effects";
import {ThreadsService} from "../../services/threads.service";
import {LOAD_USER_THREADS_ACTION, LoadUserThreadsSuccess} from "../actions";
import {Observable} from "rxjs";


@Injectable()
export class LoadUserThreadsEffectService {

  constructor(private action$: Actions, private threadsService: ThreadsService) {
  }

  @Effect()
  userThreadsEffect$: Observable<Action> = this.action$
    .ofType(LOAD_USER_THREADS_ACTION) // only react for LOAD_USER_THREADS_ACTION
    .switchMap(() => this.threadsService.loadUserThreads()) // get data from service
    .map((allUserData) => new LoadUserThreadsSuccess(allUserData)) // After get data, dispatch success action
}

 

And of course, we need to import the lib:

..
import {EffectsModule} from "@ngrx/effects";
import {LoadUserThreadsEffectService} from "./store/effects/load-user-threads.service";

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    ..
    EffectsModule.run(LoadUserThreadsEffectService),
  ],
  providers: [
    ThreadsService
  ],
  bootstrap: [AppComponent]
})
export class AppModule {
}

 

We need to change reudcer, instead of add case for 'LOAD_USER_THREAD_ACTION', we should do 'LOAD_USER_THREADS_SUCCESS':

export function storeReducer(state: AppState = INITIAL_APPLICATION_STATE, action: Action): AppState {

  switch(action.type) {
    case LOAD_USER_THREADS_SUCCESS:
          return handleLoadUserThreadsAction(state, action);
    default:
      return state;
  }
}

 

Last, in our component, we dispatch 'LoadUserThreadsAction':

  ngOnInit() {

    this.store.dispatch(new LoadUserThreadsAction())
  }

 

Github

转载于:https://www.cnblogs.com/Answer1215/p/6349021.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值