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>


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM