NGXSを用いた国家管理入門


NGXS is a state management pattern + library for Angular.

It acts as a single source of truth for your application's state, providing simple rules for predictable state mutations.

NGXS is modeled after the CQRS pattern popularly implemented in libraries like Redux and NgRx but reduces boilerplate by using modern TypeScript features such as classes and decorators.


初心者としてNGXsから始めることは、それがロケット科学の若干の種類であるというわけではなく、本質的に多くの資源が正しい方法でそれを学ぶために利用できるという事実のためであるという理由でありえません.

このチュートリアルでは、単純なCRUDアプリケーションをダミーの残りのAPIを消費する作成するためにNGXsと一緒に角度を使用します.
あなたが忍耐を実行している場合はすでに上にホップすることができますStackBlitz そして、我々が何をするつもりであるかについて、あなた自身を見てください.

必要条件

  • 角度2 +の基本的な知識が必要です.
  • Rxjsの事前知識は役に立つでしょうが、絶対に必要ではありません.
  • では始めましょう


    ステップ1:角度CLIをインストールする

    npm install -g @angular/cliORyarn add global @angular/cli新しい角度プロジェクトを作成してみましょうng new learning-ngxs

    ステップ2 : ngxsライブラリをインストールする


    プロジェクトフォルダに移動cd learning-ngxs次に、このコマンドnpm install @ngxs/store --saveまたは、あなたが糸を使っているならばyarn add @ngxs/store

    ステップ3 :プラグインのインストール(オプション)

  • このステップはオプションですが、Loggerとdevtoolが2つの非常に便利なdev依存関係であるので、あなたはそれを通過することを強く勧めます.
  • これらのプラグインは、私たちの状態が通過変更を追跡するのに役立ちます.
  • loggerとdevtoolsプラグインをインストールするには、コマンドを実行します@ngxs/logger-plugin --save & @ngxs/devtools-plugin --save-dev それぞれ.

    ステップ4 :モジュールのインポート


    これがあなたのapp.module.ts 必要なモジュールをインポートした後に
    import { NgModule } from '@angular/core';
    import { BrowserModule } from '@angular/platform-browser';
    import {HttpClientModule} from '@angular/common/http';
    import {FormsModule,ReactiveFormsModule} from '@angular/forms';
    //For NGXS
    import { NgxsModule } from '@ngxs/store';
    import { NgxsLoggerPluginModule } from '@ngxs/logger-plugin';
    import { NgxsReduxDevtoolsPluginModule } from '@ngxs/devtools-plugin';
    
    
    import { AppRoutingModule } from './app-routing.module';
    import { AppComponent } from './app.component';
    import { GeneralComponent } from './general/general.component';
    import { AppState } from './states/app.state';
    import { DesignutilityService } from './designutility.service';
    
    @NgModule({
      declarations: [
        AppComponent,
        GeneralComponent
      ],
      imports: [
        BrowserModule,
        AppRoutingModule,
        HttpClientModule,
        FormsModule,
        ReactiveFormsModule,
    
        NgxsModule.forRoot([]), NgxsLoggerPluginModule.forRoot(), NgxsReduxDevtoolsPluginModule.forRoot()
      ],
      providers: [],
      bootstrap: [AppComponent]
    })
    export class AppModule { }
    
    

    ステップ5 :コンポーネントとサービスの作成


    私たちの状態の内容を表示するためにng g c generalサーバーとの対話のための' designユーティリティ'と呼ばれるサービスを作成するGET , POST , UPDATE and DELETE データ.ng g s designutility忘れてはいけないDesignutilityService インサイドproviders アレイapp.module.ts .
    providers: [DesignutilityService]
    
    Step 4で述べたモジュールをすべてインポートしたことを確認してください.

    ステップ6 :アクションを作成する


    src @ appの中に' action 'という名前の新しいフォルダを作成します
    アクションフォルダ内で、新しいファイルを作成しますapp.action.ts
    //Here we define four actions for CRUD operations respectively
    
    //Read
    export class GetUsers {
        static readonly type = '[Users] Fetch';
    }
    
    //Create
    export class AddUsers {
        static readonly type = '[Users] Add';
        constructor(public payload: any) { }
    }
    
    //Update
    export class UpdateUsers {
        static readonly type = '[Users] Update';
        constructor(public payload: any, public id: number, public i:number) { }
    }
    
    //Delete
    export class DeleteUsers {
        static readonly type = '[Users] Delete';
        constructor(public id: number) { }
    }
    
    
    

    Actions can either be thought of as a command which should trigger something to happen, or as the resulting event of something that has already happened.

    Each action contains a type field which is its unique identifier.


    アクションは、コンポーネントからの状態への望ましい変更を行うようにディスパッチされます.
    あなたはそれに気づいたかもしれないGetUsers , 他のすべてのアクションでは、パラメータ化されたコンストラクタを持っています.
  • これらのパラメタは、行動が送られるときはいつでも、いろいろな構成要素から来ているデータだけです.
  • 例えば、AddUsers アクションのコンストラクタpayload , このペイロードは、基本的に新しいユーザに関する情報を含みます.
  • 新しく作成されたユーザーについてのこのデータは、行動にいつでも、状態の中で記憶されますAddUsers コンポーネントからディスパッチされます.
  • ステップ7 :サービスとの連携


    designutility.service.ts , 取得するには、HTTPの呼び出しを追加し、更新、追加、およびDo項目を削除します.
    このチュートリアルでは、偽のAPI呼び出しを行うためのjsonplaceholderを使用しています.
    import { Injectable } from '@angular/core';
    import {HttpClient} from '@angular/common/http';
    
    @Injectable({
      providedIn: 'root'
    })
    export class DesignutilityService {
    
      constructor(private http:HttpClient) { }
    
      fetchUsers(){
        return this.http.get('https://jsonplaceholder.typicode.com/users');
      }
    
      addUsers(userData){
        return this.http.post('https://jsonplaceholder.typicode.com/users',userData);
      }
    
      deleteUser(id:number){
        return this.http.delete('https://jsonplaceholder.typicode.com/users/'+id);
      }
    
      updateUser(payload,id:number){
        return this.http.put('https://jsonplaceholder.typicode.com/users/'+id, payload);
      }
    }
    

    ステップ8 :状態を作成する


    今このチュートリアルの最も重要な部分に到達しました.
    src ' app内の' state 'という名前の新しいフォルダを作成します.
    ステートフォルダ内で、新しいファイル名app.state.ts
    import { Injectable } from "@angular/core";
    import { Action, Selector, State, StateContext } from "@ngxs/store";
    import { DesignutilityService } from "../designutility.service";
    import { tap } from 'rxjs/operators';
    import { AddUsers, DeleteUsers, GetUsers, UpdateUsers } from "../actions/app.action";
    
    export class UserStateModel {
        users: any
    }
    
    @State<UserStateModel>({
        name: 'appstate',
        defaults: {
            users: []
        }
    })
    
    @Injectable()
    export class AppState {
        constructor(private _du: DesignutilityService) { }
    
        @Selector()
        static selectStateData(state:UserStateModel){
            return state.users;
        }
    
        @Action(GetUsers)
        getDataFromState(ctx: StateContext<UserStateModel>) {
            return this._du.fetchUsers().pipe(tap(returnData => {
                const state = ctx.getState();
    
                ctx.setState({
                    ...state,
                    users: returnData //here the data coming from the API will get assigned to the users variable inside the appstate
                })
            }))
        }
    
        @Action(AddUsers)
        addDataToState(ctx: StateContext<UserStateModel>, { payload }: AddUsers) {
            return this._du.addUsers(payload).pipe(tap(returnData => {
                const state=ctx.getState();
                ctx.patchState({
                    users:[...state.users,returnData]
                })
            }))
        }
    
        @Action(UpdateUsers)
        updateDataOfState(ctx: StateContext<UserStateModel>, { payload, id, i }: UpdateUsers) {
            return this._du.updateUser(payload, i).pipe(tap(returnData => {
                const state=ctx.getState();
    
                const userList = [...state.users];
                userList[i]=payload;
    
                ctx.setState({
                    ...state,
                    users: userList,
                });
            }))
        }
    
        @Action(DeleteUsers)
        deleteDataFromState(ctx: StateContext<UserStateModel>, { id }: DeleteUsers) {
            return this._du.deleteUser(id).pipe(tap(returnData => {
                const state=ctx.getState();
                console.log("The is is",id)
                //Here we will create a new Array called filteredArray which won't contain the given id and set it equal to state.todo
                const filteredArray=state.users.filter(contents=>contents.id!==id);
    
                ctx.setState({
                    ...state,
                    users:filteredArray
                })
            }))
        }
    }
    

    select ()について
  • The Selector() は、AppState .
  • 我々のケースでは我々はusers 内部に存在する配列AppState
  • セレクタは、Select() ステップ10に示す.
  • ステップ9:アプリの状態を文書化。モジュールです。TS


    今、私たちは創造をしているAppState , この状態を文書化する必要があるapp.module.ts ファイル.
    したがって、内部のインポート配列に移動しますapp.module.ts 必要な変更を行います.
    NgxsModule.forRoot([AppState]), NgxsLoggerPluginModule.forRoot(), NgxsReduxDevtoolsPluginModule.forRoot()
    

    Step 10 :コンポーネントの操作


    コンポーネントは、我々が我々のケースの状態の内容をコントロールするつもりであるところからの場所ですgeneral.component.ts我々は、我々の基本的なCrud活動を実行していますAppState .
    そのために、既存のユーザーを表示し、ユーザー情報を更新し、ユーザーを削除し、新しいユーザーを挿入するフォームを削除しますAppState .
    import { Component, OnInit } from '@angular/core';
    import { FormGroup, FormBuilder } from '@angular/forms';
    import { Select, Store } from '@ngxs/store';
    import { Observable } from 'rxjs';
    import { AddUsers, DeleteUsers, GetUsers, UpdateUsers } from '../actions/app.action';
    import { AppState } from '../states/app.state';
    
    @Component({
      selector: 'app-general',
      templateUrl: './general.component.html',
      styleUrls: ['./general.component.css']
    })
    export class GeneralComponent implements OnInit {
    
      //Here I have used Reactive Form, you can also use Template Driven Form instead
      userForm: FormGroup;
      userInfo: [];
      @Select(AppState.selectStateData) userInfo$: Observable<any>;
    
      constructor(private store: Store, private fb: FormBuilder) { }
    
      ngOnInit(): void {
        this.userForm = this.fb.group({
          id: [''],
          name: [''],
          username: [''],
          email: [''],
          phone: [''],
          website: ['']
        })
    
        this.store.dispatch(new GetUsers());
    
        this.userInfo$.subscribe((returnData) => {
          this.userInfo = returnData;
        })
      }
    
      addUser() {
        this.store.dispatch(new AddUsers(this.userForm.value));
        this.userForm.reset();
      }
    
      updateUser(id, i) {
    
        const newData = {
          id: id,
          name: "Siddhesh Thipse",
          username: "iamsid2399",
          email: '[email protected]',
          phone: '02138-280044',
          website: 'samplewebsite.com'
        }
    
        this.store.dispatch(new UpdateUsers(newData, id, i));
      }
    
      deleteUser(i) {
        this.store.dispatch(new DeleteUsers(i));
      }
    }
    

    重要点
  • 輸入select and store からngxs/store
  • The Select() は、AppState .
  • ユーザが削除したい場合など、目的の操作を実行するために様々な動作をどのようにディスパッチするかに注目してくださいDeleteUsers パスi パラメータとして( userid )です.
  • ユーザIDがiAppState .
  • 私はブートストラップ5を使用している部分を設計するために、しかし、UIが今のところあなたの心配でないならば、あなたはそれを完全にスキップすることができます.
    基本的なUIを作成した後general.component.html のようになります
    <div class="container-fluid">
      <h2 style="text-decoration: underline;">Getting started with NGXS</h2>
      <div class="row my-4">
        <div class="col-md-3">
          <h5 style="color: grey;">Add new user to State</h5>
          <form [formGroup]="userForm" (ngSubmit)="addUser()">
            <label class="form-label">ID</label>
            <input type="text" class="form-control mb-2" placeholder="User ID" formControlName="id">
            <label class="form-label">Name</label>
            <input type="text" class="form-control mb-2" placeholder="Enter Name" formControlName="name">
            <label class="form-label">Username</label>
            <input type="text" class="form-control mb-2" placeholder="Enter a unique username" formControlName="username">
            <label class="form-label">Email</label>
            <input type="email" class="form-control mb-2" placeholder="[email protected]" formControlName="email">
            <label class="form-label">Phone</label>
            <input type="number" class="form-control mb-2" placeholder="Enter Contact No." formControlName="phone">
            <label class="form-label">Website</label>
            <input type="email" class="form-control mb-2" placeholder="Enter website name" formControlName="website">
            <button type="submit" class="btn btn-primary btn-sm mt-2">Add User</button>
          </form>
        </div>
        <div class="col-md-9">
          <h5 style="color: grey;">User Information</h5>
          <table class="table">
            <thead>
              <tr>
                <th scope="col">ID</th>
                <th scope="col">Name</th>
                <th scope="col">Username</th>
                <th scope="col">Email</th>
                <th scope="col">Phone</th>
                <th scope="col">Website</th>
                <th scope="col">Update</th>
                <th scope="col">Delete</th>
              </tr>
            </thead>
            <tbody>
              <tr *ngFor="let contents of userInfo; index as i">
                <th scope="row">{{contents.id}}</th>
                <td>{{contents.name}}</td>
                <td>{{contents.username}}</td>
                <td>{{contents.email}}</td>
                <td>{{contents.phone}}</td>
                <td>{{contents.website}}</td>
                <td><button class="btn btn-outline-warning btn-sm" (click)="updateUser(contents.id,i)"><i
                      class="bi bi-pencil-fill"></i></button></td>
                <td><button class="btn btn-danger btn-sm" (click)="deleteUser(contents.id)"><i
                      class="bi bi-trash-fill"></i></button></td>
              </tr>
            </tbody>
          </table>
        </div>
      </div>
    </div>
    

    それは、我々は正常に我々の角度アプリケーションでの状態管理を実装している.
    今は間違いなくこれ以上のNGXsにはありますが、一度完全に基礎を理解している場合は、高度なものを学ぶのCakewalkです.
    任意の提案のincase/クエリを下にコメントを自由に感じてください.
    ソースコードはGithub