آموزش مدیریت وضعیت در انگولار با NGXS

ngxs-angular-state-management

در این مقاله قصد داریم نحوه مدیریت وضعیت ها در انگولار با NGXS را به شما آموزش بدهیم. NGXS یک روش متفاوت برای مدیریت وضعیت در انگولار است. برای مشاهده مستندات این کتابخانه به اینجا مراجعه کنید.

سرفصل های این آموزش

  1. NGXS چیست؟
  2. چرخه NGXS
  3. آموزش NGXS همراه با مثال
  4. نصب انگولار
  5. نصب NGXS Store
  6. ایجاد کامپوننت ها
  7. تعریف مدل
  8. تعریف اکشن ها
  9. تعریف یک وضعیت
  10. بروزرسانی فایل app.module.ts
  11. نمایش داده ها

NGXS چیست؟

NGXS یک الگوی مدیریت وضعیت برای فریمورک انگولار است. NGXS به عنوان یک منبع قابل اعتماد برای وضعیت برنامه های شما عمل می کند و قوانین ساده ای را برای تغییرات قابل پیش بینی وضعیت ها ارائه می دهد.

از نظر مفهومی دقیقاً همانند کتابخانه Redux است که بیشتر در برنامه های React مورد استفاده قرار می گیرد. شما نمی توانید بطور مستقیم وضعیت ها را تغییر دهید، بلکه باید یک عمل را انجام دهید و سپس از آن طریق یک وضعیت را بروزرسانی کنید. NGXS پس از الگوی CQRS که در کتابخانه ی محبوب Redux پیاده سازی شده، ساخته شده است، اما با استفاده از ویژگی های مدرن تایپ اسکریپت مانند کلاس و decorator حجم کدهای تکراری برنامه را کاهش می دهد.

چرخه NGXS

چرخه NGXS به شرح زیر است:

  1. کامپوننت های انگولار عملی (اکشن) را انجام می دهند.
  2. اگر آن عمل نیاز به تغییر داده های پایگاه داده داشت، یک درخواست به سرور ارسال کرده و عملیات مربوط به پایگاه داده را اجرا می کند.
  3. سپس بعد از دریافت پاسخ از سرور، وضعیت را تغییر می دهد. اگر back end وجود نداشت، آن عمل (اکشن) بطور مستقیم وضعیت store را تغییر داده و کامپوننت با انتخاب آن وضعیت، رابط کاربری را بروزرسانی می کند.

اگر با Redux آشنایی داشته باشید، می بینید که این چرخه همانند چرخه Redux است. برای کسب اطلاع بیشتر درباره NGXS به مستندات رسمی آن مراجعه کنید.

آموزش Angular NGXS همراه با مثال

این آموزش را با نصب انگولار توسط Angular Cli شروع می کنیم.

1- نصب انگولار

اگر قبلاً Angular Cli را بطور سراسری در سیستم تان نصب نکرده اید، با دستور زیر اینکار را انجام دهید.

npm install -g @angular/cli

# or

yarn add global @angular/cli

سپس با کد زیر یک پروژه انگولار را ایجاد کنید.

ng new ng6xs

نصب انگولار

2- نصب NGXS Store

دستور زیر را در Command Line خود وارد کرده تا NGXS نصب شود.

yarn add @ngxs/store

نصب NGXS در انگولار

حال logger-plugin و devtools-plugin را به عنوان وابستگی های توسعه، نصب کنید.

yarn add @ngxs/logger-plugin @ngxs/devtools-plugin --dev

حال این ماژول ها را به داخل فایل app.module.ts، وارد یا import کنید.

// app.module.ts

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { NgxsModule } from '@ngxs/store';
import { NgxsReduxDevtoolsPluginModule } from '@ngxs/devtools-plugin';
import { NgxsLoggerPluginModule } from '@ngxs/logger-plugin';

import { AppComponent } from './app.component';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    NgxsModule.forRoot(),
    NgxsReduxDevtoolsPluginModule.forRoot(),
    NgxsLoggerPluginModule.forRoot()
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

سپس دستور زیر را برای راه اندازی سرور توسعه انگولار اجرا کنید.

**ng serve -o

اجرای انگولار در مرورگر

همان طور که در log مرورگر می بینید، هنگامی که یک وضعیت تغییر کند، می توانیم مقادیر قدیم و جدید را مشاهده کنیم.

3- ایجاد کامپوننت ها

یک فولدر به نام components در مسیر src/app ایجاد کنید.

حال اطلاعات کاربر مانند نام و ایمیل را ایجاد و آنها را نمایش می دهیم.

ما در اینجا برای ذخیره اطلاعات کاربران از backend استفاده نمی کنیم.

بلکه باید داده ها را در Store افزوده و آن داده ها را توسط انگولار در frontend برنامه نمایش دهیم.

همچنین با اجرای دستورات زیر در انگولار دو کامپوننت ایجاد می کنیم.

ng g c components/create --spec=false
ng g c components/index --spec=false

نصب کامپوننت در انگولار

سپس با اجرای دستورات زیر در ترمینال، بوت استرپ 4 را نصب می کنیم.

yarn add bootstrap

سپس کد زیر را به فایل src/styles.css اضافه کنید.

@import "~bootstrap/dist/css/bootstrap.min.css"

در مسیر src/app/components/create کدهای زیر را به فایل create.component.html اضافه کنید.

<div class="card">
  <div class="card-body">
    <form>
      <div class="form-group">
        <label class="col-md-4">Name</label>
        <input type="text" class="form-control" #name/>
      </div>
      <div class="form-group">
        <label class="col-md-4">Email</label>
        <input type="email" class="form-control" #email/>
        </div>
        <div class="form-group">
          <button (click)="addUser(name.value, email.value)" class="btn btn-primary">Create User</button>
        </div>
    </form>
  </div>
</div>

حال این کامپوننت ها را به داخل فایل app.component.html اضافه کنید.

<div class="container">
  <div class="row">
    <div class="col-md-6">
      <app-create></app-create>
    </div>
    <div class="col-md-6"></div>
  </div>
</div>

فایل را ذخیره کرده و به آدرس localhost:4200 بروید. نتیجه آن باید مطابق تصویر زیر باشد.

ایجاد فرم بوت استرپ در انگولار

حال نیاز به ReactiveFormsModule داریم. ما در اینجا از روش Reactive به جای روش مبتنی بر قالب، استفاده می کنیم.

برای این منظور داخل فایل app.module.ts، ReactiveFormsModule را از پکیج @angular/forms اضافه می کنیم.

// app.module.ts

import { ReactiveFormsModule } from '@angular/forms';

 imports: [
    BrowserModule,
    NgxsModule.forRoot(),
    NgxsReduxDevtoolsPluginModule.forRoot(),
    NgxsLoggerPluginModule.forRoot(),
    ReactiveFormsModule
  ],

حال کدهای زیر را در فایل create.components.ts اضافه کنید.

// create.component.ts

import { Component, OnInit } from '@angular/core';
import { FormGroup, FormBuilder, Validators } from '@angular/forms';

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

  angForm: FormGroup;

  constructor(private fb: FormBuilder) {
    this.createForm();
  }

  createForm() {
    this.angForm = this.fb.group({
      name: ['', Validators.required ],
      email: ['', Validators.required ]
   });
  }

  addUser(name, email) {
    console.log(name, email);
  }

  ngOnInit() {
  }

}

و در نهایت کدهای html زیر را به فایل create.component.html اضافه کنید. 

<div class="card">
  <div class="card-body">
    <form [formGroup]="angForm">
      <div class="form-group">
        <label class="col-md-4">Name</label>
        <input type="text" class="form-control" formControlName="name" #name/>
        <div *ngIf="angForm.controls['name'].invalid && (angForm.controls['name'].dirty || angForm.controls['name'].touched)" class="alert alert-danger">
          <div *ngIf="angForm.controls['name'].errors.required">
            Name is required.
          </div>
        </div>
      </div>
      <div class="form-group">
        <label class="col-md-4">Email</label>
        <input type="email" class="form-control" formControlName="email" #email/>
        <div *ngIf="angForm.controls['email'].invalid && (angForm.controls['email'].dirty || angForm.controls['email'].touched)" class="alert alert-danger">
          <div *ngIf="angForm.controls['email'].errors.required">
            Email is required.
          </div>
        </div>
      </div>
      <div class="form-group">
        <button (click)="addUser(name.value, email.value)" 
            class="btn btn-primary"
            [disabled]="angForm.pristine || angForm.invalid">Create User</button>
      </div>
    </form>
  </div>
</div>

4- تعریف مدل

یک فولدر به نام models در مسیر src/app ایجاد کنید و داخل آن یک فایل با نام User.ts ایجاد کنید.

// User.ts

export interface User {
    name: string;
    email: string;
}

5- تعریف اکشن ها

حال یک اکشن به نام addUser ایجاد می کنیم. یک فولدر به نام actions در مسیر src/app ایجاد کرده و یک فایل با نام user.action.ts در فولدر actions ایجاد کنید.

// user.action.ts

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

export class AddUser {
    static readonly type = '[User] Add';

    constructor(public payload: User) {}
}

6- تعریف یک وضعیت

تفاوت کلیدی بین NGRX و NGXS در چگونگی مدیریت وضعیت هاست.

یک فولدر به نام state در مسیر src/app  ایجاد کرده و سپس یک فایل به نام user.state.ts در آن فولدر ایجاد کنید.

کدهای زیر را در فایل user.state.ts اضافه کنید.

// user.action.ts

import { State, Action, StateContext, Selector } from '@ngxs/store';
import { User } from '../models/User';
import { AddUser } from '../actions/user.action';

export class UserStateModel {
    users: User[];
}

@State<UserStateModel>({
    name: 'users',
    defaults: {
        users: []
    }
})
export class UserState {

    @Selector()
    static getUsers(state: UserStateModel) {
        return state.users;
    }

    @Action(AddUser)
    add({getState, patchState }: StateContext<UserStateModel>, { payload }: AddUser) {
        const state = getState();
        patchState({
            users: [...state.users, payload]
        });
    }
}

در بالا یک اکشن برای ذخیره داده های کاربر در store تعریف کردیم. هنگامی که کاربر بخواهد کاربر جدیدی را ایجاد کند، ما آن مقدار را گرفته و به آرایه وضعیت کاربرها اضافه میکنیم.

بنابراین هنگامی که کاربر ساخته شد، Store وضعیت کاربرها را بروزرسانی کرده و سپس آن وضعیت توسط کامپوننت دیگری مورد استفاده قرار میگیرد.

در این مثال آن کامپوننت index.component.ts است. بنابراین آن کامپوننت رابط کاربری را تغییر داده و کاربری که جدیداً ساخته شده را نمایش می دهد.

در نهایت، store را به داخل فایل create.component.ts، وارد یا import می کنیم.

// create.component.ts

import { Component, OnInit } from '@angular/core';
import { Store } from '@ngxs/store';
import { FormGroup, FormBuilder, Validators } from '@angular/forms';

import { AddUser } from '../../actions/user.action';

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

  angForm: FormGroup;

  constructor(private fb: FormBuilder, private store: Store) {
    this.createForm();
  }

  createForm() {
    this.angForm = this.fb.group({
      name: ['', Validators.required ],
      email: ['', Validators.required ]
   });
  }

  addUser(name, email) {
    this.store.dispatch(new AddUser({ name, email}));
  }

  ngOnInit() {
  }

}

7- بروزرسانی فایل app.module.ts

// user.state.ts

import { UserState } from './state/user.state';

imports: [
    BrowserModule,
    NgxsModule.forRoot([
      UserState
    ]),
    NgxsReduxDevtoolsPluginModule.forRoot(),
    NgxsLoggerPluginModule.forRoot(),
    ReactiveFormsModule
  ],

8- نمایش داده ها

کدهای زیر را داخل فایل index.component.ts اضافه کنید.

// index.component.ts

import { Component, OnInit } from '@angular/core';
import { Store, Select } from '@ngxs/store';
import { User } from '../../models/User';
import { Observable } from 'rxjs';

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

  users: Observable<User>;

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

  ngOnInit() {
  }

}

در بالا اگر آرایه وضعیت کاربرها تغییر کند، این کامپوننت رندر می شود و تغییرات اتفاق افتاده را نمایش می دهد.

برای مثال اگر کاربر جدیدی اضافه شود، این کامپوننت رندر شده و کاربر جدید را نمایش می دهد.

همچنین کدهای زیر را در فایل index.component.html اضافه کنید.

<div *ngIf="users">
  <table class="table table-striped">
    <thead>
      <tr>
        <th>Name</th>
        <th>Email</th>
      </tr>
    </thead>
    <tbody>
      <tr *ngFor="let user of users | async">
        <td>{{ user.name }}</td>
        <td>{{ user.email }}</td>
      </tr>
    </tbody>
  </table>
</div>

حال باید این کامپوننت را به فایل app.component.html، وارد import کنیم.

<div class="container">
  <div class="row">
    <div class="col-md-6">
      <app-create></app-create>
    </div>
    <div class="col-md-6">
      <app-index></app-index>
    </div>
  </div>
</div>

فایل را ذخیره کنید. نتیجه را در تصویر زیر می بینید.

نمایش داده های یک فرم در انگولار

به این ترتیب آموزش مدیریت وضعیت در انگولار با NGXS مان به پایان رسید.

کدهای این برنامه را می توانید از این آدرس گیت هاب دریافت کنید.

نویسنده شوید

دیدگاه‌های شما

در این قسمت، به پرسش‌های تخصصی شما درباره‌ی محتوای مقاله پاسخ داده نمی‌شود. سوالات خود را اینجا بپرسید.