ngrx/store effects 列表展示

开发流程:

开始 -> 编写数据模型 -> 编写action -> 编写redurces并配置到相应module -> 编写services -> 编写effects并配置到相应module -> 创建组件 -> 组件绑定数据模型 -> 渲染

第一步:编写数据模型(app/models/user.ts)

export class User {

  id: number;

  name: string;

}

第二步:编写action(app/actions/num.ts)

import {Action} from '@ngrx/store';
import {User} from '../models/user';

export enum ListActionType {
  Load = 'LOAD',
  LoadSuccess = 'LOAD_SUCCESS',
  RemoveUser = 'REMOVE_USER',
  RemoveUserSuccess = 'REMOVE_USER_SUCCESS',
  RemoveUserError = 'REMOVE_USER_ERROR'
}

export class Load implements Action {
  readonly type = ListActionType.Load;
}

export class LoadSuccess implements Action {
  readonly type = ListActionType.LoadSuccess;

  constructor(public payload: User[]) {
  }
}

export class RemoveUser implements Action {
  readonly type = ListActionType.RemoveUser;

  constructor(public payload: number) {
  }
}

export class RemoveUserSuccess implements Action {
  readonly type = ListActionType.RemoveUserSuccess;
}

export class RemoveUserError implements Action {
  readonly type = ListActionType.RemoveUserError;
}

第三步:编写redurcers(app/redurces/list.ts)

import {Action} from '@ngrx/store';

import {User} from '../models/user';

import {ListActionType, LoadSuccess, RemoveUser} from '../actions/list';

 

export interface State {

  loading: boolean;

  loaded: boolean;

  list: User[];

}

 

const initialState: State = {

  loading: false,

  loaded: false,

  list: []

};

 

export const list = (state = initialState, action: Action) => {

  switch (action.type) {

    case ListActionType.Load:

      console.log('load....');

      return {

        ...state,

        loading: true,

      };

    case ListActionType.LoadSuccess:

      console.log('load success');

      const myA = (<LoadSuccess>action).payload;

      console.log(myA);

      return {

        ...state,

        loaded: true,

        loading: false,

        list: myA

      };

    case ListActionType.RemoveUser:

      console.log('remove user');

      const userId = (<RemoveUser>action).payload;

      state.list = state.list.filter(function (item) {

        return item.id !== userId;

      });

      return {...state};

 

    default:

      return state;

  }

};

配置redurcer(app/app.module.ts)

imports: [

    BrowserModule,

    RouterModule.forRoot(routes),

    StoreModule.forRoot({ modelNum, list}),      //配置redurcer

  ],

第四步:编写services(app/services/ListService.ts)

import {Injectable} from '@angular/core';

import {HttpClient} from '@angular/common/http';

import {Observable} from 'rxjs/Observable';

import {User} from '../models/user';

 

 

@Injectable()

export class ListService {

  public getList(): Observable<any> {

    return this.http.get<{ users: User[] }>('/api/users.json');

  }

 

  public removeUser(): Observable<any> {

    return Observable.create(function (observer) {

      observer.next('true');

    });

  }

 

  constructor(private http: HttpClient) {

  }

}

第五步:编写effects:

import {Injectable} from '@angular/core';

import {Actions, Effect, ofType} from '@ngrx/effects';

import {Observable} from 'rxjs/Observable';

import {Action} from '@ngrx/store';

import {ListActionType, Load, LoadSuccess, RemoveUser, RemoveUserError, RemoveUserSuccess} from '../actions/list';

import {catchError, map, switchMap} from 'rxjs/operators';

import {ListService} from '../services/ListService';

import {of} from 'rxjs/observable/of';

 

 

@Injectable()

export class ListEffects {

 

  @Effect()

  loadList$: Observable<Action> = this.action$.pipe(   //rxjs写法。loadList$是effect名,在外部没有用到,可以随便起。

    ofType<Load>(ListActionType.Load),

    switchMap(action => {

      return this.listService.getList().pipe(map(

        users => {

          return new LoadSuccess(users);

        }

      ));

    })

  );

 

  @Effect()

  removeUser$: Observable<Action> = this.action$.pipe(

    ofType<RemoveUser>(ListActionType.RemoveUser),

    switchMap(_ => {

      return this.listService.removeUser().pipe(

        map(res => {

          console.log(res);

          if (res === 'true') {

            return new RemoveUserSuccess();

          } else {

            return new RemoveUserError();

          }

        }),

        catchError(err => of(new RemoveUserError()))

      );

    })

  );

 

 

  constructor(private action$: Actions, private listService: ListService) {

  }

 

}

解析:loadList$ effects 通过actions stream 监听所有的派发的actions,但是使用ofType之后,只对 ListActionType.Load 感兴趣。然后使用switchMap()来将action stream映射到一个新的observable对象。this.listService.getList()会返回一个observable,这个observable会将movies映射到一个新的action new LoadSuccess,若错误发生,返回一个空对象。如果需要进行状态更改,这个action会被派发到store,由reducer处理。

 

EffectsModule.forRoot( ) 必须在AppModule下注册,如果不需要注册任何根级别的Effect,可以Provider一个空数组EffectsModule.forRoot( ) 必须在AppModule下注册,如果不需要注册任何根级别的Effect,可以Provider一个空数组

 

记得在app.module.ts配置effects和HttpClient:


// app.module.ts

import { HttpClientModule } from '@angular/common/http';
import { BrowserModule } from '@angular/platform-browser';
import { Action, ActionReducer, combineReducers, StoreModule } from '@ngrx/store';
import { ListEffects } from './effects/list.effects';

imports: [

    BrowserModule,

    StoreModule.forRoot({modelNum, list}),

    EffectsModule.forRoot([ListEffects]),

    HttpClientModule

  ],


// app.module.ts

import { HttpClientModule } from '@angular/common/http';
import { BrowserModule } from '@angular/platform-browser';
import { Action, ActionReducer, combineReducers, StoreModule } from '@ngrx/store';
import { ListEffects } from './effects/list.effects';

imports: [

    BrowserModule,

    StoreModule.forRoot({}),

    EffectsModule.forRoot([]),

    HttpClientModule

  ],


//admin.module.ts

import { EffectsModule } from '@ngrx/effects';
import { HttpClientModule } from '@angular/common/http';
import { ListEffects } from './effects/list.effects';
 
@NgModule({
  imports: [
    StoreModule.forFeature('common', reducerWrapper),
    EffectsModule.forFeature([ ListEffects ]),
    HttpClientModule,
  ],
})
export class MovieModule {}

const combinedReducer: ActionReducer<CommonState, Action> =
    combineReducers(COMMON_REDUCERS);

export function reducerWrapper(
    state: CommonState, action: Action): CommonState {
    return combinedReducer(state, action);
}

//reducers  root.ts

export const selectOrderState = Store.createFeatureSelector<CommonState>('common');

通过forRoot 或forFeature 多次运行一个effect class,并不会导致effect会运行多次。forRoot和forFeature的加载效果在功能上是没有区别的,二者的区别在于forRoot设置了effects 所需的providers

 

第六步:创建组件

ng g component list

第七步、第八步:组件绑定数据模型

组件ts文件:

import {Component, OnInit} from '@angular/core';

import {Store} from '@ngrx/store';

import * as list from '../actions/list';

import {State} from '../reducers/list';

import {User} from '../models/user';

 

@Component({

  selector: 'app-list',

  templateUrl: './list.component.html',

  styleUrls: ['./list.component.scss']

})

export class ListComponent implements OnInit {

 

  public list: User[];

 

  constructor(private store: Store<any>) {

    this.store.select('list').subscribe(_list => {

      if (_list) {

        console.log(_list);

 

        console.log(_list.list);

 

        this.list = _list.list;

      }

    });

  }

 

  removeUser(id) {

    console.log(id);

    this.store.dispatch(new list.RemoveUser(id));

  }

 

  ngOnInit() {

    this.store.dispatch(new list.Load());

  }

}

组件html文件:

<div>

list

  请尝试点击上半部分的li。

  <ul>

    <li *ngFor="let item of list" (click)="removeUser(item.id)">{{item.name}}</li>

  </ul>

  <app-list-body></app-list-body>

  <br/>

  <a routerLink="/model">to counter demo</a>

</div>

最后配置路由:

import {Routes} from '@angular/router';

import {IndexComponent} from './index/index.component';

import {ModelDemoComponent} from './model-demo/model-demo.component';

import {ListComponent} from './list/list.component';

 

 

export const routes: Routes = [

  {

    path: 'list',

    component: ListComponent

  },

  {

    path: 'model',

    component: ModelDemoComponent

  },

  {

    path: '**',

    redirectTo: 'list'

  }

];

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值