راهنمای کامل State management در فریم‌ورک انگولار

قبلا طی پستی مفهوم ریداکس به زبون ادمی زاد توضیح دادیم! حالا می خواهیم ببنیم چطور می تونیم این مفاهیم رو در یک اپ انگولاری پیاده سازی کنیم. برای مدیریت استیت (State) در انگولار چهار کتابخانه معروف و خوب وجود داره NgRx، Akita, NGXS و حتی خود RxJS نیز می توان استفاده کرد. حالا بیاید بررسی شون کنیم.

شما باید آشنایی که با Redux (مطلب قبلی) داشته باشید و همچنین تجربه کار با انگولار را در چندین پروژه داشته باشید تا بتوانید از آموزه های این مقاله استفاده کنید.

http://vrgl.ir/wF3Jc

تصور کنید - کتابها استیت های مختلف اپ هستند که درون یک کتابخانه مدیریت استیت، مدیریت شده اند
تصور کنید - کتابها استیت های مختلف اپ هستند که درون یک کتابخانه مدیریت استیت، مدیریت شده اند

در این مقاله، مفهوم مدیریت حالت را شرح داده و می گوییم که چگونه Akita به ما کمک می کند که به گردش داده در اپ به وسیله مدیریت کردن اون سرعت می‌بخشه. خب قبلش شاید بپرسید مدیریت State (حالت) چی هس؟ خب توجه کنید به تعریف ماشین حالت:

A state machine is any device that stores the status of something at a given time and can operate on input to change the status and/or cause an action or output to take place for any given change. — The State Machine

ماشین حالات، به هر وسیله ای که وضعیت چیزی را در یک زمان معین ذخیره کند و می تواند روی ورودی برای تغییر وضعیت و یا انجام یک عمل یا خروجی برای هر تغییری که شکل می گیرد، کار کند.

- ماشین حالت

دایره ها حالتهای مختلف و a اکشنی است که موجب گذار حالت می شود. - درس شیرین نظریه زبان ها و ماشین ها :))
دایره ها حالتهای مختلف و a اکشنی است که موجب گذار حالت می شود. - درس شیرین نظریه زبان ها و ماشین ها :))

به زبانی ساده، حالت (State) هر نوع فرمی از داده را ذخیره و گذار حالت را بر مبنای حالت جاری و اکشن، مدیریت می کند.

با مفاهیم گفته شده در عمل آشنا خواهیم شد.

چرا مدیریت حالت ضروری است؟

وب اپ ها دارن غنی تر و پیچیده تر میشن، همین موجب سخت شدن مدیریت حالت به شکل نمایی می شود.

بخش های مختلف یک اپلیکیشن مسئولیت های متفاوتی دارند، و اونا (کامپوننت ها، دایرکتیو، و...) در بین فایل های مختلف از هم جدا شده اند، اما همه اونا نیاز دارند که به یک حالت دسترسی داشته باشند.

یک کتابخونه مدیریت حالت راه راحتی را برای:

  • مدل کردن حالت اپ
  • گرفتن مقادیر محاسبه شده از آن
  • مانیتور کردن تغییرات

سومندی های زیادی رو برامون داره از جمله normalize = نرمال سازی داده (جلوگیری از افزونگی داده)، immutability یا غیر قابل تغییر بودن و سازمندهی گزار حالت و...

انتخاب یک کتابخانه برای مدیریت حالت (State)

اول RxJS، سادگی زیادی داره [+] ولی در پروژه های بزرگ قابل استفاده نیست، چرا که شما نیاز به نوشتن کد زیادی برای انجام یک کار دارید، در حالی که کتابخانه های دیگه با کشیدن انتزاع (Abstraction) روی آن کار ما را راحت کرده اند. از جمله معروف ترین و پر استفاده ترین کتابخونه ها NgRx است.

توسعه دهندگان Akita، بر این باور بوده اند که شیب تند یادگیری [Steep learning curve] (به معنی سختی یادگیری) NgRx و اینکه برای افزودن یک ویژگی کوچک نیازی به نوشتن کدهایی است که باید باشند (Boilerplate) تا بخواهیم تازه کدهای خودمان را بنویسیم، باعث شده برای حذف پیچیدگی های NgRx یک کتابخانه جدید توسعه دهند. [+]

LEARNING CURVE + BOILERPLATE
LEARNING CURVE + BOILERPLATE

و نکته بعدی این است که Akita بر منبای اصول طراحی شی گرا نوشته شده در حالی که NgRx با رویکرد برنامه نویسی فانکشنال توسعه داده شده، بنابراین افرادی که تجربه برنامه نویسی شی گرا را دارند راحت‌تر می‌توانند با آن ارتباط برقرار کنند.

حسی که من موقع استفاده از NgRx دارم :)
حسی که من موقع استفاده از NgRx دارم :)

مورد آخر هم کتابخونه NGXS زمانی برای کاهش پیچیدگی های NgRx به وجود اومد، اما با اومدن Akita تقریبا میشه گفت حرفی برای گفتن نداره، چرا که اکیتا بر پایه سادگی است، به طوریکه هم تازه کارها و هم توسعه دهندگان با تجربه می تونن یادش بگیرن و به راحتی ازش استفاده کنند.[+]

البته اگر در پروژه هایتان از react،vue یا sevlte استفاده میکنید می توانید باز از Akita استفاده کنید.

امیدواریم که تا الان راضی شده باشید که Akita رو انتخاب کنیم! و در ادامه راجبش حرف بزنیم. اگه هنوز شک دارید برای مقایسه کتابخونه های مدیریت state، این مطلب رو بخونید.

معماری Akita

معماری
معماری

دو کامپوننت اصلی در Akita عبارت اند از: Store و Query

می تونید فرض کنید که Store مثل یک جدول که داده ها در پایگاه داده نگه داری می کند است و کارهایی مانند درج و به‌روزرسانی داده و... را انجام می دهد.

مورد بعدی Query راهی برای درخواست داده از Store است.یک کوئری می تونه با بقیه کوئری های دیگه حرف بزنه و ترکیب شون (Join) باعث بشه که یه کویری پیچیده تر ایجاد بشه.

کامپوننت به شکل reactive (واکنش‌پذیر) در حال گرفتن داده است. ما (تیم توسعه Akita) بر این باوریم که نیازی نیست کامپوننت منبع داده خود را بشناسد، به همین منظور نیازی به تزریق store به داخل کامپوننت (مانند NgRx) نیست، اما تغییرات store رو با استفاده از سرویس ها داریم.

اینطور است که ما به یک جریان داده ی یک طرفه (Redux) با یک معماری دقیق می رسیم.

?
?

حالا که با مبانی بسیار ساده Akita آشنا شدیم، بهتره که طی یک پروژه کلی چیزهای هیجان انگیز رو تجربه کنیم و یادشون بگیریم!

نصب Akita

برای شروع کافیه یه پروژه انگولار با CLI ایجاد کنید و کار رو شروع کنید.

نصب با یک دستور

ng add @datorama/akita

ساخت فرم ورود کاربران Login

ایجاد store برای احرازهویت

دو نوع store در Akita داریم. store پایه که هر نوع شکلی از داده رو در خودش نگه داری می کنه و entity store نیز برای ذخیره سازی داده های یک موجودیت بکار می رود. یک موجودیت شامل همه اعمال CRUD (ایجاد، خوانش، به‌روزرسانی، حذف) روی داده های آن می شود.

ساخت store پایه

ما در اینجا برای Login از یک store پایه استفاده می کنیم. جهت ساخت، دستور زیر را بزنید.

ng g akita-schematics:feature auth/auth --plain

یا خیلی ساده‌تر

ng g af auth/auth --plain

یا خیلی خیلی ساده تر!

akita

با زدن فلگ plain یک store پایه ایجاد می شود. حالت پیشفرض (بدون فلگ plain) برایمان entity store می سازد. خروجی دستور بالا ساخت یک پوشه به اسم state داخل auth و ایجاد فایل های store, query, servic است.

فایل Auth Store

کارمان را با ساخت مدل state (شامل نام و توکن برگشت داده شده از سمت سرور) و نوشتن حالت آغازین در store ادامه میدهیم.

// Step 1
export interface AuthState {
 name: string;
 token: string;
}

export function createInitialState(): AuthState {
 return {
    name: null,
    token: null
  };
}

فایل Auth Query

در قسمت auth.query نیز نیاز داریم بدانیم که کاربر چه موقه حالت لاگین آن عوض می شود، پس:

$isLoggedIn = this.select(state => !!state.token); // 1

 isLoggedIn() {
    return !!this.getValue().token; // 2
  }

1. توجه داشته باشید که تابع select، تغییرات بخش در خواستی (token) مربوط به state در قالب Obervable بهمون بر می گردونه،

2. درحالی که تابع getValue فقط مقدار را بر می گردونه بدون نیاز به subscribe کردن روی آن

فایل Auth Service

و در نهایت در سرویس، تابع ورود و خروج را پیاده سازی می کنیم. با استفاده از تابع update (از توابع توکار Akita) استور را به روزرسانی می کنیم.

login(cred: { username: string, password: string }) {
  // در خواست به api
 // return this.http
 //   .post(`${API}/login` cred)
 //   .pipe(tap((authState: AuthState) => this.authStore.update(authState)));
 
 // جعل درخواست لاگین
 return of({ name: cred.username, token: '1234' }).pipe(
   tap((authState: AuthState) => this.authStore.update(authState)) //  به‌روزرسانی استور
    );
  }

 logout() {
   this.authStore.reset(); // بازگشت به حالت آغازین
}

کامپوننت لاگین

خیلی ساده فرم زیر رو می سازیم.

 <form [formGroup]="loginForm" (ngSubmit)="submit()">
    <input type="email" formControlName="email">
    <input type="password" formControlName="password">
    <button type="submit" class="btn btn-primary">Submit</button>
    <div class="alert-danger" *ngIf="error">    {{error}}  </div>
  </form> 

و حالا پیاده سازی درون فایل login.component.ts

 error: string | null = null; 
 
 constructor (
                      private authService: AuthService,
                      private router: Router
                     ) {}
                      
  submit() {
   this.error = null;
    if ( this.loginForm.valid ) {
      this.authService.login(this.loginForm.value).subscribe({ next: ({ name }) => {   
                 this.router.navigateByUrl('/'); // successful login!
                 console.log(` Welcome ${name} `)
             },
                 error: (error) => { this.error = error.error.errorMsg; }
          });
       }
    } 

ابتدا بررسی می کنیم که فرم valid باشه، بعد با استفاده از سرویس auth متد login را فراخوانی می کنیم. اگه جواب درخواستمون ? بود، یک پیغام خوش آمد گویی به کاربر در کنسول چاپ می شود، و گرنه متن خطا را زیر دکمه Submit نمایش می دهیم.

منابع: [+, +, +]



خب فکر کنم تا اینجا کافی باشه برای این مقاله، در سری بعد بیشتر راجبش خواهیم گفت. (در مورد موضوع مقاله بعدی، ایده بدید!)

شما راجب Akita چی فکر می کنید؟ نظرتون راجب این پست چیه؟ ممنون میشم فیدبک هاتونو تو نظرات بگید. همچنین این پست رو ❤️ کنید و به اشتراک بزارید :)


? به جامعه انگولار ایران بپیوندید!