mohammadsharifi.com
راهنمای کامل State management در فریمورک انگولار
قبلا طی پستی مفهوم ریداکس به زبون ادمی زاد توضیح دادیم! حالا می خواهیم ببنیم چطور می تونیم این مفاهیم رو در یک اپ انگولاری پیاده سازی کنیم. برای مدیریت استیت (State) در انگولار چهار کتابخانه معروف و خوب وجود داره NgRx، Akita, NGXS و حتی خود RxJS نیز می توان استفاده کرد. حالا بیاید بررسی شون کنیم.
شما باید آشنایی که با Redux (مطلب قبلی) داشته باشید و همچنین تجربه کار با انگولار را در چندین پروژه داشته باشید تا بتوانید از آموزه های این مقاله استفاده کنید.
در این مقاله، مفهوم مدیریت حالت را شرح داده و می گوییم که چگونه 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
ماشین حالات، به هر وسیله ای که وضعیت چیزی را در یک زمان معین ذخیره کند و می تواند روی ورودی برای تغییر وضعیت و یا انجام یک عمل یا خروجی برای هر تغییری که شکل می گیرد، کار کند.
به زبانی ساده، حالت (State) هر نوع فرمی از داده را ذخیره و گذار حالت را بر مبنای حالت جاری و اکشن، مدیریت می کند.
با مفاهیم گفته شده در عمل آشنا خواهیم شد.
چرا مدیریت حالت ضروری است؟
وب اپ ها دارن غنی تر و پیچیده تر میشن، همین موجب سخت شدن مدیریت حالت به شکل نمایی می شود.
بخش های مختلف یک اپلیکیشن مسئولیت های متفاوتی دارند، و اونا (کامپوننت ها، دایرکتیو، و...) در بین فایل های مختلف از هم جدا شده اند، اما همه اونا نیاز دارند که به یک حالت دسترسی داشته باشند.
یک کتابخونه مدیریت حالت راه راحتی را برای:
- مدل کردن حالت اپ
- گرفتن مقادیر محاسبه شده از آن
- مانیتور کردن تغییرات
سومندی های زیادی رو برامون داره از جمله normalize = نرمال سازی داده (جلوگیری از افزونگی داده)، immutability یا غیر قابل تغییر بودن و سازمندهی گزار حالت و...
انتخاب یک کتابخانه برای مدیریت حالت (State)
اول RxJS، سادگی زیادی داره [+] ولی در پروژه های بزرگ قابل استفاده نیست، چرا که شما نیاز به نوشتن کد زیادی برای انجام یک کار دارید، در حالی که کتابخانه های دیگه با کشیدن انتزاع (Abstraction) روی آن کار ما را راحت کرده اند. از جمله معروف ترین و پر استفاده ترین کتابخونه ها NgRx است.
توسعه دهندگان Akita، بر این باور بوده اند که شیب تند یادگیری [Steep learning curve] (به معنی سختی یادگیری) NgRx و اینکه برای افزودن یک ویژگی کوچک نیازی به نوشتن کدهایی است که باید باشند (Boilerplate) تا بخواهیم تازه کدهای خودمان را بنویسیم، باعث شده برای حذف پیچیدگی های NgRx یک کتابخانه جدید توسعه دهند. [+]
و نکته بعدی این است که Akita بر منبای اصول طراحی شی گرا نوشته شده در حالی که 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 چی فکر می کنید؟ نظرتون راجب این پست چیه؟ ممنون میشم فیدبک هاتونو تو نظرات بگید. همچنین این پست رو ❤️ کنید و به اشتراک بزارید :)
? به جامعه انگولار ایران بپیوندید!
- کانال انگولار ایران
- گروه انگولار ایران
- توییتر انگولار ایران
- و ما را در اینجا فالو کنید!
فرانتاِند دوستداشتنی من (یکبار کد بزن)
? نظرسنجی وضعیت توسعهدهندگان Front-end ایرانی
آیا استفاده از SSR برای داشتن SEO بهتر در وب اپلیکیشن ها تنها راه ممکنه؟