之前我們都是先講原理再來呈現實作
新的週期我們顛倒過來,將會優先進行程式開發操作的手順在進行原理的心得分享
首先我們先在core
中建立一個資料夾store
,並且建立三個資料夾action
、effect
、reducer
core/
| |-store
| | |-action
| | |-effect
| | |-reducer
然後在action中建立兩個檔案index.ts
和layout.action.ts
core/
| |-store
| | |-action
| | | |-index.ts
| | | |-layout.action.ts
然後我們在layout.action.ts
中建立兩個Action,分別用在Loading與我們的伸縮側邊表單Menu
layout.action.ts
import { createAction, props } from '@ngrx/store';
import { SlideMenuStatus } from 'src/app/shared/types/layout-setting/layout';
/**
* 更新系統遮罩狀態
*/
export const UPDATE_LOADING_STATUS = createAction(
'[LAYOUT] UPDATE_LOADING_STATUS',
props<{ Status: boolean }>()
);
/**
* 更新系統選單狀態狀態
*/
export const UPDATE_MENU_STATUS = createAction(
'[LAYOUT] UPDATE_MENU_STATUS',
props<{ Status: SlideMenuStatus }>()
);
假如是透過copy+paste貼在自己的檔案中的朋友,這時候@ngrx/store
應該出現讀不到的狀況,這是正常的,我們現在需要自己安裝
npm i '@ngrx/store
安裝完之後就可以正常載入了
建立完之後我們在reducer
中新增一個檔案叫做layout.reducers.ts
並在裡面註冊兩個reducer監聽事件
core/
| |-store
| | |-reducers
| | | |-index.ts
| | | |-layout.reducers.ts
layout.reducers.ts
import { createReducer, on } from '@ngrx/store';
import { UPDATE_LOADING_STATUS, UPDATE_MENU_STATUS } from '../actions/layout.action';
import { SlideMenuStatus } from 'src/app/shared/types/layout-setting/layout';
/**
*layout State初始化狀態
*/
export const initialState: State = {
Loading: false,
SlideMenuStatus: {
isShow: true,
isExtant: true,
isMini: false,
},
};
/**
*layout State Type
*/
export interface State {
Loading: boolean;
SlideMenuStatus: SlideMenuStatus;
}
/**
*監聽Reducer
*/
export const reducer = createReducer(
initialState,
on(UPDATE_LOADING_STATUS, (state, action) => {
return {
...state,
Loading: action.Status,
};
}),
on(UPDATE_MENU_STATUS, (state, action) => {
return {
...state,
SlideMenuStatus: action.Status,
};
})
);
接下來就是Angular Standalone作為核心的載入模式了
在之前我們都是使用app.module.ts
進行引用的
Angular version<=16
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';
import { StoreModule } from '@ngrx/store';
ort { reducer } from './core/store/reducers';
@NgModule({
declarations: [AppComponent],
imports: [
BrowserModule,
StoreModule.forRoot({ layout: reducer.layout })
],
providers: [],
bootstrap: [AppComponent],
})
export class AppModule {}
而在我們的Angular Standalone開發環境中,我們可以在app.config.ts
中進行這部分參數的處理
事實上在以Standalone作為核心的系統開發流程中,原先大部分被app.module.ts
進行引用與管理的絕大部分都被抽離至app.config.ts進行application層級的使用,而非在原先的NgModule進行管理
Platform
Application
NgModule
Directive / Component
這其實就是我能夠局部還原環境的原因所在,當我原先依賴於root注入的ngModule被抽離至上一層的狀況,我就能更好的將我的功能專注於當前Component與他所依賴的ngModule之中
具體app.config.ts的內容如下
app.config.ts
import { ApplicationConfig } from '@angular/core';
import { provideRouter } from '@angular/router';
import { routes } from './core/routes/app.routes';
import { provideStore } from '@ngrx/store';
import { reducer } from './core/store/reducers';
export const appConfig: ApplicationConfig = {
providers: [
provideRouter(routes),
provideStore({
layout: reducer.layout,
}),
],
};
然後他會在main.ts
進行注入至application層級的動作
import { bootstrapApplication } from '@angular/platform-browser';
import { appConfig } from './app/app.config';
import { AppComponent } from './app/app.component';
bootstrapApplication(AppComponent, appConfig)
.catch((err) => console.error(err));
這時候在回到我們的layoutComponent中,將Store進行注入,好取得被放入在系統中的資料
layout.component.ts
import { Component, inject } from '@angular/core';
import { CommonModule } from '@angular/common';
import { Observable, Subject, takeUntil } from 'rxjs';
import { Store } from '@ngrx/store';
import * as fromPagesReducers from '../../../core/store/reducers';
@Component({
standalone: true,
imports: [CommonModule],
templateUrl: './shopping-home.component.html',
styleUrls: ['./shopping-home.component.scss'],
})
export class layoutComponent {
private store = inject(Store<fromPagesReducers.State>);
private destroy$ = new Subject<void>();
loading$: Observable<boolean> = this.store
.select((x) => x.layout.Loading)
.pipe(takeUntil(this.destroy$));
}
假如有開發或是看過先前版本Angular的朋友有沒有覺得現在的開發多麼簡潔明瞭XD
我不用透過ngModule特別去管理Module,也不用特別透過constructor去做Service的宣告(甚至還有官方建議上限
然後我們在樣板上進行宣告,由於他是一個Observable
所以我們需要用async
的pipe進行訂閱管理
layout.component.html
<app-header></app-header>
{{ loading$ | async | json }}
這時候在看我們的頁面就會看到在layout.reducers.ts
中進行初始化的State中所帶的值,
可以在這裡停一下,想想看究竟是什麼值
答案如下
export const initialState: State = {
Loading: false, //<== 這個
SlideMenuStatus: {
isShow: true,
isExtant: true,
isMini: false,
},
};
很好 我們已經會了怎麼建立起一個系統層級的資料管理脈絡,接下來我將會在後續的內容中講解Observable、Observe、Subject的訂閱狀態,以及在訂閱資料中好用的rxjs小工具與技巧
當然還有Action、Effect、Reducer三大狀態管理管道