ngxs 状态管理器

简单的安装 @ngxs/schematics

$ ng add @ngxs/schematics
$ ng g ngxs-sk --spec  // 会生成一个 src/store 文件
  1. 配置 src/store 下的config文件 (完成todo)。
  2. 在Core模块中导入NgxsStoreModule模块,没有创建Core就直接在AppModule中导入。

ng6,rxjs6.0.0,ngxs3.0.1

λ ng new ngxs  --style=styl --routing --skip-install
λ cd ngxs
λ yarn
λ yarn add @ngxs/store
λ yarn add @ngxs/logger-plugin @ngxs/devtools-plugin --dev
λ ng g c template1
λ ng g c template2
λ code .

在app下创建 app=>ngxs[actions, models, state] 3个文件夹

models

// model.ts

 //  存储数据模型
export interface Tutorial {
  name: string;
  url: string;
}

actions

// action.ts

import { Tutorial } from '../models/tutorial.model';

export class AddTutorial {

  // 需要一个唯一的标识
  static readonly type = '[TUTORIAL] Add';

  // 函数接收的参数
  constructor(public payload: Tutorial) { }
}

export class RemoveTutorial {
  static readonly type = '[TUTORIAL] Remove';

  constructor(public payload: string) { }
}

state

// state.ts

import { State, Action, StateContext, Selector } from '@ngxs/store';

// models
import { Tutorial } from '../models/tutorial.model';

// actions
import { AddTutorial, RemoveTutorial } from '../actions/tutorial.actions';

// state
export class TutorialStateModel {
  tutorials: Array<Tutorial>;
}

@State<TutorialStateModel>({
  name: 'tutorials',
  defaults: {
    tutorials: []
  }
})
export class TutorialState {
  @Selector()
  static getTutorials(state: TutorialStateModel) {
    return state.tutorials;
  }

  // 接收一个事件模型
  @Action(AddTutorial)
  // add(stateContext, arguments)
  add({
    getState, patchState }: StateContext<TutorialStateModel>,
    { payload }: AddTutorial) {
    const state = getState();
    patchState({
      tutorials: [...state.tutorials, payload]
    });
  }

  // 接收一个事件模型
  @Action(RemoveTutorial)
  remove({
    getState, patchState }: StateContext<TutorialStateModel>,
    { payload }: RemoveTutorial) {
    patchState({
      tutorials: getState().tutorials.filter(a => a.name !== payload)
    });
  }
}

app.module.ts

import { NgxsModule } from '@ngxs/store';
import { TutorialState } from './ngxs/state/tutorial.state';
import { NgxsReduxDevtoolsPluginModule } from '@ngxs/devtools-plugin';
import { NgxsLoggerPluginModule } from '@ngxs/logger-plugin';

@NgModule({
  imports: [
    NgxsModule.forRoot([
      TutorialState
    ]),
    NgxsReduxDevtoolsPluginModule.forRoot(),
    NgxsLoggerPluginModule.forRoot()
  ]
})
export class AppModule { }

组件内使用数据

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

import { Observable } from 'rxjs/observable';

import { Store, Select } from '@ngxs/store';
import { TutorialState } from '../ngxs/state/tutorial.state';
import { Tutorial } from '../ngxs/models/tutorial.model';
import { RemoveTutorial } from '../ngxs/actions/tutorial.actions';


@Component({
  selector: 'app-template2',
  templateUrl: './template2.component.html',
  styleUrls: ['./template2.component.styl']
})
export class Template2Component implements OnInit {

  // tutorials$: Observable<Tutorial>;

  // Select 直接映射数据事件
  @Select(TutorialState.getTutorials) tutorials$: Observable<Tutorial>;

  constructor(private store: Store) {
    // this.tutorials$ = this.store.select(state => state.tutorials.tutorials);
  }

  delTutorial(name) {
    this.store.dispatch(new RemoveTutorial(name));
  }

  ngOnInit() { }
}

模板渲染

<ul *ngIf="tutorials$">
    <li *ngFor="let item of tutorials$ | async">
      name: {{ item.name}}
      <br> url: {{ item.url }}
    </li>
</ul>

发出单个字符串

// state.ts
export class TitleModel {
  title: string;
}

@State<TitleModel>({
  name: 'title',
  defaults: {
    title: 'hello Ajanuw'
  }
})
export class TitleState {
  @Selector()
  static getTitle(state: TitleModel) {
    return state.title;
  }
}

// app.module.ts
import { UsersState , TitleState} from './ngxs-store/state/users.state';
NgxsModule.forRoot([UsersState, TitleState]),

// component.ts
import { User, Title } from '../ngxs-store/models/users.model';
@Select(TitleState.getTitle) title$: string;

// component.html
<h2> {{ title$ | async }} </h2>

事件触发其他事件

使用状态上下文对象中包含dispatch的函数

// 代码片段

export class UserInfoState {
  @Selector()
  static userinfs(state: UserInfoModel) {
    return state.userinfos;
  }
  @Action(AddUserInfo)
  add(
    { getState, patchState, dispatch }: StateContext<UserInfoModel>,
    { userInfo }: AddUserInfo,
  ) {
    const state = getState();
    patchState({
      userinfos: [...state.userinfos, userInfo],
    });
    dispatch(new UserInfoCount()); // 这里
  }

  @Action(UserInfoCount)
  count({ getState }: StateContext<UserInfoModel>) {
    const state = getState();
    console.log(state.userinfos.length);
  }
}

异步事件

// promise

export class UserInfoState {
  @Action(AddUserInfo)
  async add(
    { getState, patchState }: StateContext<UserInfoModel>,
    { userInfo }: AddUserInfo,
  ) {
    const userinfo = await this.checkRepeatName(userInfo); // 硬编码2s后得到结果
    const state = getState();
    patchState({
      userinfos: [...state.userinfos, userinfo],
    });
  }

  // 添加用户信息时检查用户名是否已经存在,(具体实现不重要)
  private checkRepeatName(userInfo: UserInfo): Promise<UserInfo> {
    return new Promise(resolve => {
      setTimeout(() => {
        resolve(userInfo);
      }, 2000);
    });
  }
}
// Observable

export class UserInfoState {
  @Selector()
  static userinfs(state: UserInfoModel) {
    return state.userinfos;
  }
  @Action(AddUserInfo)
  add(
    { getState, patchState }: StateContext<UserInfoModel>,
    { userInfo }: AddUserInfo,
  ) {
    return this.checkRepeatName(userInfo).pipe(
      tap((userinfo: UserInfo) => {
        const state = getState();
        patchState({
          userinfos: [...state.userinfos, userinfo],
        });
      }),
    );
  }

  // 添加用户信息时检查用户名是否已经存在,(具体实现不重要)
  private checkRepeatName(userInfo: UserInfo): Observable<UserInfo> {
    return of(userInfo).pipe(delay(2000));
  }
}

事件回掉

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

import { Store, Select } from "@ngxs/store";
import { UserInfoState, UserInfoModel } from "./shared/store/user.state";
import { Observable } from "rxjs";
import { UserInfo } from "./shared/store/user.model";
import { AddUserInfo } from "./shared/store/user.action";
import { FormBuilder, FormGroup, Validators } from "@angular/forms";

const l = console.log;
@Component({
  selector: "app-root",
  templateUrl: "./app.component.html",
  styleUrls: ["./app.component.styl"],
})
export class AppComponent implements OnInit {
  @Select(UserInfoState.userinfs)
  public userinfos$: Observable<UserInfo>;

  public userinfoFrom: FormGroup = this.fb.group({
    name: [
      "",
      {
        validators: [Validators.required],
      },
    ],
    age: [
      "",
      {
        validators: [
          Validators.required,
          Validators.max(100),
          Validators.min(18),
        ],
      },
    ],
  });
  public get name() {
    return this.userinfoFrom.get("name");
  }
  constructor(private store: Store, private fb: FormBuilder) {}

  ngOnInit(): void {}

  public addUserInfo(e: HTMLFormElement): void {
    const userinfo: UserInfo = this.userinfoFrom.value;
    this.store
      .dispatch(new AddUserInfo(userinfo))
      .subscribe((v: UserInfoModel) => { // 这里
        e.reset();
      });
  }
}
<div>
  <form
    action=""
    [formGroup]="userinfoFrom"
    (ngSubmit)="addUserInfo(form)"
    #form
  >
    <div>
      <input type="text" placeholder="name" formControlName="name" /><span
        *ngIf="
          name.invalid && (name.dirty || name.touched) && !!name.errors.required
        "
        >name必填</span
      >
    </div>
    <div><input type="number" placeholder="age" formControlName="age" /></div>
    <div>
      <button type="submit" [disabled]="!userinfoFrom.valid">Submit</button>
    </div>
  </form>
</div>
<ul>
  <li *ngFor="let el of (userinfos$ | async)">{{ el.name }} - {{ el.age }}</li>
</ul>
posted @ 2018-05-05 00:02  Ajanuw  阅读(1930)  评论(0编辑  收藏  举报