ستمنحك هذه المقالة فهمًا متعمقًا لمدير حالة Angular NgRx وستقدم لك كيفية استخدام NgRx وآمل أن يكون ذلك مفيدًا لك!
NgRx هو حل معماري Redux لإدارة الحالة العالمية في التطبيقات Angular. [البرامج التعليمية الموصى بها: "البرنامج التعليمي الزاوي"]
@ngrx/store: وحدة إدارة الحالة العالمية
@ngrx/ Effects: التعامل مع الآثار الجانبية
@ngrx/store-devtools: أداة تصحيح أخطاء المتصفح، تحتاج إلى الاعتماد على ملحق Redux Devtools
@ngrx/schematics: أداة سطر الأوامر لإنشاء ملفات NgRx بسرعة
@ngrx/entity: تحسين كفاءة المطورين في تشغيل البيانات في المخفض
@ngrx/router-store: مزامنة حالة التوجيه مع المتجر العالمي
1. قم بتنزيل NgRx
npm install @ngrx/store @ngrx/effects @ngrx/entity @ngrx/router-store @ngrx/store-devtools @ngrx/schematics
2. تكوين NgRx CLI
ng config cli.defaultCollection @ngrx/schematics
// الزاوي.json "كلي": { "defaultCollection": "@ngrx/schematics" }
3. إنشاء المتجر
ng g store State --root --module app.module.ts --statePath store --stateInterface AppState
4. إنشاء الإجراء
ng g action store/actions/counter --skipTests
استيراد { createAction } من "@ngrx/store" زيادة قيمة التصدير = createAction("increment") تصدير const decrement = createAction("decrement")
5. إنشاء المخفض
ng g reducer store/reducers/counter --skipTests --reducers=../index.ts
استيراد { createReducer، on } من "@ngrx/store" استيراد { إنقاص، زيادة } من "../actions/counter.actions" تصدير const counterFeatureKey = "العداد" حالة واجهة التصدير { عدد : عدد } حالة التصدير الأولية: الحالة = { العدد: 0 } مخفض قيمة التصدير = createReducer( الحالة الأولية, على (الزيادة، الحالة => ({ العد: الحالة. العد + 1 })))، على (التناقص، الحالة => ({ العد: الحالة. العد - 1 })) )
6. إنشاء محدد
ng g selector store/selectors/counter --skipTests
استيراد { createFeatureSelector، createSelector } من "@ngrx/store" استيراد {counterFeatureKey, State} من "../reducers/counter.reducer" استيراد {AppState} من ".." تصدير const SelectCounter = createFeatureSelector<AppState, State>(counterFeatureKey) تصدير const SelectCount = createSelector(selectCounter,state =>state.count)
7. تقوم فئة المكون بتشغيل الإجراء والحصول على الحالة
استيراد {حدد، متجر} من "@ngrx/store" استيراد {يمكن ملاحظته} من "rxjs" استيراد { AppState } من "./store" استيراد {تناقص، زيادة} من "./store/actions/counter.actions" استيراد {selectCount} من "./store/selectors/counter.selectors" فئة التصدير AppComponent { العدد: يمكن ملاحظته<رقم> مُنشئ (متجر خاص: Store<AppState>) { this.count = this.store.pipe(select(selectCount)) } زيادة () { this.store.dispatch(increment()) } إنقاص () { this.store.dispatch (تناقص ()) } }
8. حالة عرض قالب المكون
<button (click)="increment()">+</button> <span>{{ العد |.غير متزامن }}</span> <button (click)="decrement()">-</button>
1. استخدم الإرسال في المكون لتمرير المعلمات عند تشغيل الإجراء، وسيتم وضع المعلمات في النهاية في كائن الإجراء.
this.store.dispatch(increment({count: 5 }))
2. عند إنشاء وظيفة Action Creator، احصل على المعلمات وحدد نوع المعلمة.
استيراد { createAction، الدعائم } من "@ngrx/store" زيادة قيمة الزيادة = createAction("increment"، الدعائم<{ count: number }>())
تصدير دعائم وظيفة الإعلان<P يمتد الكائن>(): Props<P>;
3. الحصول على المعلمات من خلال كائن الإجراء في المخفض.
مخفض قيمة التصدير = createReducer( الحالة الأولية, على (الزيادة، (الحالة، الإجراء) => ({ العد: State.count + action.count })) )
metaReducer عبارة عن ربط بين الإجراء -> المخفض، مما يسمح للمطورين بمعالجة الإجراء مسبقًا (يتم استدعاؤه قبل استدعاءات وظائف المخفض العادية).
وظيفة تصحيح الأخطاء (المخفض: ActionReducer<any>): ActionReducer<any> { وظيفة الإرجاع (الحالة، الإجراء) { مخفض الإرجاع (الحالة، الإجراء) } } تصدير وحدات metaReducers: MetaReducer<AppState>[] = !environment.production ؟[تصحيح] : []
المتطلبات: إضافة زر إلى الصفحة بعد النقر على الزر، تأخير ثانية واحدة حتى تزيد القيمة.
1. أضف زرًا لزيادة القيمة غير المتزامنة في قالب المكون بعد النقر فوق الزر، يتم تنفيذ طريقة increment_async
.
<button (click)="increment_async()">غير متزامن</button>
2. أضف طريقة increment_async
إلى فئة المكون وقم بتشغيل الإجراء لتنفيذ عمليات غير متزامنة في الطريقة.
increment_async() { this.store.dispatch(increment_async()) }
3. قم بإضافة إجراء لتنفيذ عمليات غير متزامنة في ملف الإجراء.
تصدير const increment_async = createAction("increment_async")
4. قم بإنشاء تأثير، واستقبل الإجراء وقم بتنفيذ الآثار الجانبية، واستمر في تشغيل الإجراء
ng g effect store/effects/counter --root --module app.module.ts --skipTests
يتم توفير وظيفة التأثير بواسطة وحدة @ngrx/effets، لذلك يجب استيراد تبعيات الوحدة ذات الصلة في الوحدة الجذرية.
استيراد {Injectable} من "@angular/core" استيراد { الإجراءات، createEffect، ofType } من "@ngrx/effets" استيراد {increment, increment_async} من "../actions/counter.actions" استيراد { mergeMap، خريطة } من "rxjs/operators" استيراد {المؤقت} من "rxjs" // createEffect // يُستخدم لإنشاء التأثير، ويستخدم التأثير لإجراء التأثيرات الجانبية. // قم بتمرير وظيفة رد الاتصال عند استدعاء الطريقة، وأعد الكائن الذي يمكن ملاحظته في وظيفة رد الاتصال. كائن الإجراء الذي سيتم تشغيله بعد تنفيذ التأثيرات الجانبية // يستمر إرجاع القيمة المرجعة لوظيفة رد الاتصال داخل createEffect. الطريقة، ويتم تخزين قيمة الإرجاع النهائية في خصائص فئة التأثير // بعد إنشاء مثيل لفئة التأثير، سيشترك NgRx في خصائص فئة التأثير عند اكتمال التأثيرات الجانبية، سيحصل على كائن الإجراء المراد تشغيله وتشغيل الإجراء. //الإجراءات // عندما يقوم أحد المكونات بتشغيل إجراء، يحتاج التأثير إلى تلقي الإجراء من خلال خدمة الإجراءات، لذلك في فئة التأثير، يتم حقن كائن مثيل فئة خدمة الإجراءات في فئة التأثير من خلال معلمة المُنشئ // المثيل كائن فئة خدمة الإجراءات هو كائن يمكن ملاحظته، عند تشغيل إجراء، سيتم إصدار كائن الإجراء نفسه كدفق بيانات // ofType // قم بتصفية كائن الإجراء الهدف. // المعلمة هي وظيفة منشئ الإجراء للإجراء الهدف // إذا لم تتم تصفية كائن الإجراء الهدف، فلن يستمر إرسال دفق البيانات هذه المرة // إذا تمت تصفية كائن الإجراء الهدف، فإن كائن الإجراء سيستمر إرسالها كدفق بيانات @Injectable() فئة التصدير التأثيرات المضادة { منشئ (الإجراءات الخاصة: الإجراءات) { // this.loadCount.subscribe(console.log) } LoadCount = createEffect(() => { إرجاع هذا.actions.pipe( من النوع(increment_async)، mergeMap(() => timer(1000).pipe(map(() => increment({ count: 10 })))) ) }) }
1. نظرة عامة
تتم ترجمة الكيان ككيان، والكيان هو جزء من البيانات في المجموعة.
يوفر NgRx كائنات محول الكيان، ويتم توفير طرق مختلفة لكيانات التشغيل في المجموعة ضمن كائنات محول الكيان.
2. الأساسية
1. EntityState: واجهة نوع الكيان
/* { المعرفات: [1، 2]، الكيانات: { 1: {المعرف: 1، العنوان: "مرحبًا Angular" }، 2: {المعرف: 2، العنوان: "مرحبًا NgRx" } } } */ حالة واجهة التصدير تمتد EntityState<Todo> {}
2. createEntityAdapter: إنشاء كائن محول الكيان
3. EntityAdapter: واجهة نوع كائن محول الكيان
محول ثابت التصدير: EntityAdapter<Todo> = createEntityAdapter<Todo>() // احصل على الحالة الأولية. يمكنك تمرير معلمات الكائن أم لا. تصدير ثابت الحالة الأولية: الحالة = محول.getInitialState ()
3. طريقة المثيل
https://ngrx.io/guide/entity/adapter#adapter-collection-methods
4. المحدد
// SelectTotal يحصل على عدد عناصر البيانات // يحصل SelectAll على جميع البيانات ويقدمها في شكل مصفوفة // يحصل SelectEntities على مجموعة الكيانات ويقدمها في شكل قاموس // يحصل SelectIds على مجموعة المعرفات ويقدمها في شكل مصفوفة const {selectIds, SelectEntities,selectAll,selectTotal } = محول .getSelectors();
تصدير const SelectTodo = createFeatureSelector<AppState, State>(todoFeatureKey) تصدير const SelectTodos = createSelector(selectTodo, SelectAll)
1. مزامنة حالة التوجيه
1) تقديم الوحدات
استيراد { StoreRouterConnectingModule } من "@ngrx/router-store" @NgModule({ الواردات: [ StoreRouterConnectingModule.forRoot() ] }) تصدير فئة AppModule {}
2) دمج حالة التوجيه في المتجر
استيراد * كـ fromRouter من "@ngrx/router-store" واجهة التصدير AppState { جهاز التوجيه: fromRouter.RouterReducerState } مخفضات قيمة التصدير: ActionReducerMap<AppState> = { جهاز التوجيه: fromRouter.routerReducer }
2. قم بإنشاء محدد للحصول على حالة التوجيه
// router.selectors.ts استيراد { createFeatureSelector } من "@ngrx/store" استيراد {AppState} من ".." استيراد { RouterReducerState، getSelectors } من "@ngrx/router-store" const SelectRouter = createFeatureSelector<AppState, RouterReducerState>( "جهاز التوجيه" ) ثابت التصدير { // الحصول على المعلومات المتعلقة بالمسار الحالي (معلمات التوجيه، وتكوين التوجيه، وما إلى ذلك) حددالطريق الحالي, // احصل على المحتوى بعد الرقم # في شريط العناوين SelectFragment، // احصل على معلمات استعلام التوجيه SelectQueryParams، // احصل على معلمة استعلام محددة SelectQueryParam('name') حددQueryParam, // احصل على معلمات التوجيه الديناميكية SelectRouteParams, // احصل على معلمة توجيه ديناميكية محددة SelectRouteParam('name') حددRouteParam, // احصل على البيانات المخصصة للمسار، حدد RouteData، // احصل على عنوان الوصول الفعلي للمسار SelectUrl } = getSelectors(selectRouter)
// home.component.ts استيراد {حدد، متجر} من "@ngrx/store" استيراد {AppState} من "src/app/store" استيراد {selectQueryParams} من "src/app/store/selectors/router.selectors" فئة التصدير AboutComponent { مُنشئ (متجر خاص: Store<AppState>) { this.store.pipe(select(selectQueryParams)).subscribe(console.log) } }