简单的安装
> 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.tsimport { 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.tsimport { State, Action, StateContext, Selector } from '@ngxs/store';// modelsimport { Tutorial } from '../models/tutorial.model';// actionsimport { AddTutorial, RemoveTutorial } from '../actions/tutorial.actions';// stateexport class TutorialStateModel { tutorials: Array;}@State ({ name: 'tutorials', defaults: { tutorials: [] }})export class TutorialState { @Selector() static getTutorials(state: TutorialStateModel) { return state.tutorials; } // 接收一个事件模型 @Action(AddTutorial) // add(stateContext, arguments) add({ getState, patchState }: StateContext , { payload }: AddTutorial) { const state = getState(); patchState({ tutorials: [...state.tutorials, payload] }); } // 接收一个事件模型 @Action(RemoveTutorial) remove({ getState, patchState }: StateContext , { 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; // Select 直接映射数据事件 @Select(TutorialState.getTutorials) tutorials$: Observable ; constructor(private store: Store) { // this.tutorials$ = this.store.select(state => state.tutorials.tutorials); } delTutorial(name) { this.store.dispatch(new RemoveTutorial(name)); } ngOnInit() { }}
模板渲染
- name: { { item.name}} url: { { item.url }}
发出单个字符串
// state.tsexport class TitleModel { title: string;}@State({ name: 'title', defaults: { title: 'hello Ajanuw' }})export class TitleState { @Selector() static getTitle(state: TitleModel) { return state.title; }}// app.module.tsimport { UsersState , TitleState} from './ngxs-store/state/users.state';NgxsModule.forRoot([UsersState, TitleState]),// component.tsimport { User, Title } from '../ngxs-store/models/users.model';@Select(TitleState.getTitle) title$: string;// component.html { { title$ | async }}
事件触发其他事件
使用状态上下文对象中包含dispatch的函数
// 代码片段export class UserInfoState { @Selector() static userinfs(state: UserInfoModel) { return state.userinfos; } @Action(AddUserInfo) add( { getState, patchState, dispatch }: StateContext, { userInfo }: AddUserInfo, ) { const state = getState(); patchState({ userinfos: [...state.userinfos, userInfo], }); dispatch(new UserInfoCount()); // 这里 } @Action(UserInfoCount) count({ getState }: StateContext ) { const state = getState(); console.log(state.userinfos.length); }}
异步事件
// promiseexport class UserInfoState { @Action(AddUserInfo) async add( { getState, patchState }: StateContext, { userInfo }: AddUserInfo, ) { const userinfo = await this.checkRepeatName(userInfo); // 硬编码2s后得到结果 const state = getState(); patchState({ userinfos: [...state.userinfos, userinfo], }); } // 添加用户信息时检查用户名是否已经存在,(具体实现不重要) private checkRepeatName(userInfo: UserInfo): Promise { return new Promise(resolve => { setTimeout(() => { resolve(userInfo); }, 2000); }); }}
// Observableexport class UserInfoState { @Selector() static userinfs(state: UserInfoModel) { return state.userinfos; } @Action(AddUserInfo) add( { getState, patchState }: StateContext, { userInfo }: AddUserInfo, ) { return this.checkRepeatName(userInfo).pipe( tap((userinfo: UserInfo) => { const state = getState(); patchState({ userinfos: [...state.userinfos, userinfo], }); }), ); } // 添加用户信息时检查用户名是否已经存在,(具体实现不重要) private checkRepeatName(userInfo: UserInfo): Observable { 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; 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(); }); }}
- { { el.name }} - { { el.age }}