NgRx แแแแแแแแฃแ แแ
แแแแแแก แกแแแแฎแแแแ แแแแแแแ แแ แแแฃแแแ
แจแแกแแแแแ
แแฃ แแแแฃแแแ แแแแแแแแแ แแก แแแแแแกแแแแ แแแแแแแแแแแ แแแแแ, แแแแแ แแแแแฎแแแ แแฆแฌแแ แ, แกแแแแช NgRx-แแก แชแแแแ แแแ แแแแฃแกแแ แแแแแแแ. แแแฃแฎแแแแแแ แแแแกแ, แแแแ แ แแแแฌแงแแแ แแแแแแแแแ แ แแ แแแฃแ แแแก NgRx-แก, แแ แแแกแ แกแฌแแแแ แฃแแ แแแแ แแ แแกแแญแแ แแ แแแแฉแแแ. แแแแก แแ แแแ แกแแแแ แแฃแแแ NgRx-แแก แแ แแ แจแแฎแแแแแ แ แแฃแแ, แซแแแแแ แฉแแฎแแแ แแฃแแ แกแขแ แฃแฅแขแฃแ แแ. แกแแแแแแแแแแจแ NgRx แแ แแก แซแแแแแ แแซแแแแ แ แฎแแแกแแฌแงแ, แ แแแแแแช แแแแฃแแแ แแ แแแแแแแแแแแขแก แซแแแแแ แแแแ แขแแแแแก, แแแแกแแแฃแแ แแแแ แแแ แแแแแแแชแแแแแ แแฃแแแฃแ แ แแฃแจแแแแแก แแ แแก.
แ แแแแแแแแแ แแแฃแแแ, แ แแ แแชแแแแ Angular-แแกแ แแ RxJs-แแก แกแแคแฃแซแแแแแ, แกแแแแ NgRx-แก แแแแชแแแแแ.
แ แ แแ แแก NgRx?
NgRx แแ แแก แแแแแแแแแแ, แ แแแแแแช แแแแฎแแแ แแแ แแแแแแแชแแแก แกแแแแแแก (State) แแแแแฏแแแแขแจแ. แแฃ แฌแแ แแแแแแแแแ, แ แแ แฉแแแแ แแแแแแแชแแ แแ แแก แแแแฅแแแ, แแแจแแ แกแแแแแ แแ แแก แงแแแแแคแแ แ, แ แแกแ แแแแแแแ แแแแแช แจแแแซแแแแ แแแแฅแแแแจแ แจแแแชแแแแแก. แแแแแแแแแ, แกแแญแแก, แแแแแชแแ, แแแแแแ แแแแก แ แแแแแแแแ, แกแแฉแฅแแ แ, แแแแแแแ, แกแแ แแแก แแแแแชแแ แแ แ.แจ. NgRx-แแ แกแแกแขแแแฃแ แแ แแ แแ แแแแแแแแฃแแแ แจแแแแแซแแแ แแแแแกแแแฆแแ แแ, แ แ แฃแแแ แแแแแแแแก แแแแฅแแแแ, แ แแชแ แแซแฆแแแ แแแแฅแแแแก แแแฅแแฅแแแก, แกแแฉแฅแแ แแก แแแแแ แแแแก แแ แกแแญแแก แแแแขแ แแแแแแก.
แกแแแแแแซแ แชแแแแแแ
- Action - แแฅแจแแแ แแ แแก แฃแแแแแแฃแ แ แแแแแแแ แ แแแแแแช แแแแชแแแ แแแแแแแแแขแแแแกแ แแ แกแแ แแแกแแแแกแแแ (แแแแแแแแแ แกแแแจแ แแแแแแก แแแแแขแแแ, แฌแแจแแ, แคแแแแแก แแขแแแ แแแ แแ แกแฎแแ).
- Reducer - แกแแแแแแก แชแแแแแแแแก แฃแแ แฃแแแแแงแแคแก แฌแแแแแ แคแฃแแฅแชแแแแแก แแ แแแแแแแแ, แ แแแแแกแแช แ แแแแฃแกแแ แ แแฌแแแแแ. แแกแแแ แแฆแแแแ แแแแแแแแ แ แกแแแแแก แแ แฃแแฎแแแก แแฅแจแแแก, แ แแแ แแแแแแแแแแ แแฎแแแ แกแแแแแ.
- Selectors - แฌแแแแแ แคแฃแแฅแชแแแแ, แ แแแแแแแช แแแแแแงแแแแแ แกแแแแแแก แแแฌแแแแแแก แแกแแฆแแแแ แแ แจแแกแแแแแแแ.
- Store - แกแแแแแ แฎแแแแแกแแฌแแแแแแ Store-แแก แกแแจแฃแแแแแแ, แ แแแแแแช แกแแแแแแก แแแแแแ แแแแแแ แแแกแขแแแชแแแ แแ แแแแกแแแแแแ แแก แแแแแ แแแแแ แแแแ แแฅแจแแแแแก.
- Effects - แแคแแฅแขแแแ แแ แแก แแ แแแแแ แ แแแแ แแแแ แแแแแแแแแ, แ แแแแแแแช แแฅแจแแแแแแก แแแ แแแแแฃแ แแ แฎแแ แชแแแแแแแ. แแกแแแ แแ แแ แแฎแ แแ, แฃแกแแแแแ แแฅแจแแแแแก, แ แแแ API-แก แแแฃแแแแจแแ แแแแ แแ แกแแแแแแแ แแแแ แแชแแแแ แฉแแแขแแ แแ แแแแแแแชแแแก แแแฆแแ, แฎแแแ แแแแ แ แแฎแ แแ, แแแแแ แแแกแชแแแแ แแฅแจแแแแแก, แ แแชแ, แแแแแแแแแ แฌแแ แแแขแแแแ แแแแแแแแก แแแแแชแแแแแ, แ แแแแแแแช แฃแแแ แแแแแแแชแแแก แกแแแแแจแ แแแแแแแแกแแ.
แแ แงแแแแแคแ แแก แกแแแแฃแกแขแ แแชแแแ NgRx-แแก แแแแฃแแแแขแแชแแ แแแแแแแแแแก แจแแกแแแแจแแแ แกแฅแแแแก:
แแแแกแแแแ แฌแแ แขแแแแ แแแแแแแแแขแ แแแแฆแแ แแแ แชแฎแแแ แฅแแแแ แแฃแแฎแแแแ. แ แแแแ แช แแฎแแแแแ, แแแแแแแแแขแ แกแแแแฅแขแแ แแกแแแ แแฆแแแก แกแแแแแแก แจแแกแแฎแแ แแแคแแ แแแชแแแก, แแแแแแแแแ แแแกแแแแแแแแแ แกแแฅแแแแแแก แกแแแก. แแแแแก แแฎแ แแ แแแแแแแแแขแ แแแกแชแแแก แแฅแจแแแแแก, แกแแแแช แแแแฎแแแ แแแคแแ แแแชแแ, แ แแแแแแช แแฎแแ แกแแแแแแ แฃแแแ แแแกแแฎแแก, แแแแแแแแแ แแฎแแแ แแแกแแแแแแแแแแก แกแแฅแแ. แแฅแจแแแแแ แฃแแแแจแแ แแแแ แ แแแแฃแกแแ แแแกแ แแ แแคแแฅแขแแแก. แแฃ แแแแแแแชแแ แแแชแแแฃแแ แแฅแจแแแแ แแ แฃแแแ แแแฃแแแแจแแ แแแก API-แก, แแแจแแ แแก แแแ แแแแแ แ แแแแฃแกแแ แจแ แแแแแแแก, แแแแ แแ แแฃ แกแแ แแแ แแแ แแแแแแจแแ แแแ แแแญแแ แแแแ - แแแฅแแแ แแฎแแแ แแแกแแแแแแแแแ แกแแฅแแ แแแแแชแแแแ แแแแแจแ แฃแแแ แแแกแแฎแแ - แแแจแแ แแฅแจแแแ (แ แแแแฃแกแแ แแแ แแ แแแ) แแคแแฅแขแแแกแแช แแแแแแแก. แแฃแแชแ, แฃแคแ แ แกแฌแแ แ แแฅแแแแ แแแแก แแฅแแ, แ แแ แแ แแฅแจแแแก แแคแแฅแขแแแ แแแแคแแฅแกแแ แแแก. แแแแแชแแแแ แแแแแกแแแ แแแแฃแแแแแชแแแก แแแ แแแแแฃแ แแ แฉแแแ แแแแแแ แแแแฎแแแ แแแแแก แแแฉแแแแแ, แ แแ แแฎแแแ แแแแแ แแแแ แฉแแแขแแแ แแแแ, แแกแแ แแ แแฅแจแแแแ แแคแแฅแขแแแ แแ แแแ แ แแแแฃแกแแ แแช แฃแแแ แแแแแ แแก, แ แแแ แแแแแแแแแก แแแแแแแ แแแแ แแกแแฎแแก แกแแแแแจแ, แแแแแแแแแ แฉแแขแแแ แแแแก แกแแแแแ แ. แแฅแจแแแแแแแ แแ แแคแแฅแขแแแ แแ แแแแแแแแแ แแ แแฎแ แแแแ แแแแแแจแแ แแแฃแแแ. แแก แแแแขแแ แฎแแแแ, แ แแ แแคแแฅแขแแแ, แ แแชแ แแกแแแ แแฅแจแแแก แแแแฆแแแแ, แกแแ แแแกแก แแงแแแแแแ, แ แแแ แแแฃแแแแจแแ แแแแ API-แก แแ แแแกแแแ แแแแฆแแ แแแกแฃแฎแ, แฌแแ แแแขแแแแ แแแแแแขแ แแฃ แแ แ แแฎแแแ แแแแแ. แ แแชแ แแแกแฃแฎแก แแแแฆแแแแ, แแกแแแ แแแแแ แแแกแชแแแแ แแฅแจแแแก, แแแแแแแแแ แแฅแจแแแก, แ แแแแแแช แแแแฃแแแแแ, แ แแ แแฎแแแ แแแแแ แฌแแ แแแขแแแแ แแแแแแขแ แแแแแชแแแแ แแแแแจแ. แแก แแฅแจแแแแช แแแแแแแก แ แแแแฃแกแแ แก, แ แแแแแแช แแฎแแ แแแแแขแแแฃแ แแแแแก แแแแฎแแแ แแแแแก แกแแแจแ แแกแแฎแแแก, แฎแแแ แฉแแขแแแ แแแแก แกแแแแแ แก - แ แแแแแแช แแแ แแแแ แแฅแจแแแแ แแแแแฉแแแแ แกแแแแแจแ - แแแแฅแ แแแก. แแ แงแแแแแคแ แแก แแแแจแ แแ แแก แกแแแ แ, แ แแแแแแช แฃแแแแ แคแแแแ แ แแแแฃแกแแ แแแแก แแแแ แแแแแแฃแจแแแแแฃแ แแแแแชแแแแแก แแกแแฎแแแก แกแแแแแจแ แแ แแ แกแแแแแแก แจแแกแแฎแแ แแแคแแ แแแชแแแก แแแแฌแแแแก แกแแแแฅแขแแ แแก แกแแจแฃแแแแแแ. แแ แฃแแแแแกแแแแแก แแงแแแแแก แแแแแแแแแขแ, แ แแแแแแช แกแแแแแก แแกแแฎแแแก แแแแแแแชแแแจแ. แแกแ แจแแแแ แ แฉแแแแ แกแแแแแแก แแแแแฏแแแแขแแก แชแแแแ. แแ แแฅแขแแแแจแ แแก แงแแแแแคแแ แ แฃแคแ แ แแแแแแ แแแฎแแแแ.
แฉแแแแ แแแแแแแชแแ
แ แแแ แแแแแแแชแแแก แแแแแแแ แแแแแแขแ แแ แ แแ แแแแฎแแ แฏแแ, แแแแแแแงแแแแแ แฌแแแแกแฌแแ แแแแแฃแ แแ แแแฅแขแก, แ แแแแแก แแแแแช แจแแแแซแแแแ แฉแแแแฌแแ แแ แแแแฐแแแแก แ แแแแแแขแแ แแแแแ (ngrx-starter branch). แแ แแแแแแแฌแงแแแ npm install
แแ แซแแแแแแก แแแจแแแแ. แแแแแแแชแแ แแแฅแแแแแ แแแแแแฃแ แคแแแแก แแงแแแแแก - database/db.json. แแ แฃแแแแแกแแแแแแก แกแแ แแแ แแ แแแแฅแขแแฃแ แแแ แจแแแแซแแแแ แแ แซแแแแแแ json-server --watch database/db.json
. json-server แจแแแแแฅแแแแก แแแแแแฃแ แกแแ แแแ แก แแแแแชแแแแ แแแแแ, แ แแแแแแแแแช แแแแแแแชแแ HTTP แแแแฎแแแแแแก แแแแแแแก. แแแแก แจแแแแแ แแแแ แ แขแแ แแแแแแแก แแแกแขแแแชแแแจแ แแแฃแจแแแ ng serve
.
แแแแแแแชแแแก แกแขแ แฃแฅแขแฃแ แ:
src/app
โโโ app.component.css
โโโ app.component.html
โโโ app.component.ts # แแแแแแ แ แแแแแแแแแขแ. แงแแแแ แกแฎแแ แแแแแแแแแขแ
โโโ app.module.ts # แแแกแจแแ แแแแแแแกแแแฃแแ.
โโโ input # แแฎแแแ แแแกแแแแแแแแ แกแแฅแแแก แแแกแแแแขแแแแแ แแแแ.
โ โโโ input.component.css # แฃแจแฃแแแแ แแงแแแแแก ItemsService-แก.
โ โโโ input.component.html
โ โโโ input.component.ts
โโโ item # แแแกแแแแแแแแแ แกแแฅแแแก แแแแแแแแแขแ, แจแแแชแแแก
โ โโโ item.component.css # แฌแแจแแแก แฆแแแแแก แแ แแแแแฎแแแแแก แคแฃแแฅแชแแแก.
โ โโโ item.component.html # แฃแจแฃแแแแ แแงแแแแแก ItemsService-แก.
โ โโโ item.component.ts
โโโ item.model.ts # แแแกแแแแแแแแแแก แกแแฅแแแก แแแแแแ
โโโ items.service.ts # แกแแ แแแกแ, แ แแแแแแช แฃแแแแจแแแแแ API-แก
แแ แแฉแฅแแ แแ, แแแแแแแแแแ แแ แแแแแแแชแแ แแ แแแฎแแ แ แแแแ แแฃแจแแแแก แแแกแ แแแแแแฃแแ แแแแแแแแแขแ.
แแแแแแแชแแแจแ แแแแ แ แแ แแกแแกแฃแ แแแแ แแแขแแ แแแ. แแแแแแแแแ, แกแแ แแแกแแแก แแแแแแฃแแ แแแขแแ แ แแแแแแแแแขแ แฃแจแฃแแแแ แแงแแแแแก. subscribe
แแแแแแ แแแแ แฏแแ แแ แแแแแงแแแแแฃแแ ts แคแแแแแแจแ. แแแแกแแแแแแ, แกแแ แแแกแจแ แแแงแ แแแแแแ แกแแแฏแแฅแแแแก, แ แแแแแแช แงแแแแ HTTP แแแแฎแแแแแแ แฃแแแ แแแแแแแแแแ แแแแแฎแแแแฃแแ แแแแแแแแก แกแแแ, แ แแแแแกแแช AppComponent แฃแกแแแแก. NgRx แแแแแแฎแแแ แแแ, แ แแ แแแแแแแแแแแขแแก แกแแฃแแแแแกแ แแแขแแ แแแแ แแแแแแแงแแแแ, แ แแแ แแแฅแกแแแแแฃแ แแ แแแแ แแแแ แแแแ แแแฃแฌแแกแ แแแแแแ แแ แแแฃแแแแแ แแแแก.
แแแ แแแแ แแแแแฏแแแ
แแแแแแแกแขแแแแ แแ NgRx. แฉแแแ แแแแแญแแ แแแแ แแแแแแ แ แแแแฃแแ, ngrx/store
แแ แแคแแฅแขแแแแก แแแแฃแแ ngrx/effects
. แแแแกแแแแแแ ngrx/store-devtools
-แก แแแแแแแงแแแแแ แแแแแแแแแแแขแแก แแ แแก, แ แแแ แแ แแฃแแแ แแแแ แแแแแแแแ แแแ แกแแแแแก. แแแแกแแแแแก แฅแ แแแแ แแแแญแแ แแแแแ Redux แแฅแกแแแแจแแแแก แแแงแแแแแ.
npm install @ngrx/effects @ngrx/store @ngrx/store-devtools
แแแแแ แแแแกแขแ แแ แแ แแกแแแ แแแแฃแแจแ:
app.module.ts
// ... other imports
import { StoreModule } from "@ngrx/store";
import { StoreDevtoolsModule } from "@ngrx/store-devtools";
@NgModule({
declarations: [AppComponent, ItemComponent, InputComponent],
imports: [
// ... other imports
StoreModule.forRoot([]),
StoreDevtoolsModule.instrument({
maxAge: 25, // Retains last 25 states
logOnly: environment.production,
autoPause: true, // Pauses recording actions and state changes when the extension window is not open
}),
],
providers: [],
bootstrap: [AppComponent],
})
export class AppModule {}
แกแแแ แแก แงแแแแ แแแแแแแแแขแแกแแแแก แฉแแแ แชแแแแแฃแแ แคแแแแแ แ แแแแฅแแแแ, แ แแแแแแแช store-แแก แคแแแแแ แจแ แแแแงแ แแแ แแแแก.
src/app/store
โโโ actions
โโโ effects
โโโ reducers
โโโ selectors
โโโ state
โโโ util
แแฎแแ แแแแแแ แ แแแแฎแแแ แกแแแแแ แแแแแฌแงแแ. แแแฎแกแแแก แฉแแแแ แแแแขแแ แแ แแ แแ แจแแกแแแแจแแแแ แ แฉแแแ แแแแชแ NgRx-แก แ แแชแ แแแแแแกแแแแ: โแแฃ แแ แแชแ แ แแแ แแแแฌแงแ, แแฅแจแแแแแแ แแแแฌแงแโ.
แแฅแจแแแแแแก แคแแแแแ แจแ แจแแแฅแแแแ todo.actions.ts. แแฎแแ แแแแคแแฅแ แแแ แแแแแ, แแฃ แ แ แแแฅแแแแแแแแ แจแแแซแแแแ แแแแแฎแแ แชแแแแแก แแแแฎแแแ แแแแแแ. แแแแฎแแแ แแแแแก แฃแแแ แจแแแซแแแก แแแแแแแแก แแแฎแแ, แแฎแแแ แแแแแแก แแแแแขแแแ, แแแกแ แฌแแจแแ แแ แจแแชแแแ.
store/actions/todo.actions.ts
import { createAction, props } from "@ngrx/store";
import { Item } from "src/app/item.model";
export const addItem = createAction(
"[Todo Page] Add Item",
props<{ description: string }>()
);
export const deleteItem = createAction(
"[Todo Page] Delete Item",
props<{ id: number }>()
);
export const updateItem = createAction(
"[Todo Page] Update Item",
props<{ item: Item }>()
);
export const getItems = createAction("[Todo Page] Get Items");
แฉแแแ แแฅแจแแแก แแแแฅแกแแแ แขแแแ แ แแแแ แช แชแแแแแก. แชแแแแแ แแแแแก แแฎแ แแ แแฅแแแแแ createAction
แคแฃแฅแแชแแแ, แ แแแแแแช แแแ แแแแขแ แแ แแฆแแแก แแฅแจแแแแก แขแแแก (แแแก แแแฎแแกแแแแแแแก) แแ แแ แแแแแก (แแ แแแคแแ แแแชแแแก แขแแแก, แ แแแแแแช แแ แแฅแจแแแก แฃแแแ แแแแแขแแแแ). แแแแแแแชแแฃแ แแ แแแกแแฌแงแแกแจแ แแแแฃแแฎแแ แคแ แฉแฎแแแแแจแ แแฌแแ แแแ แแฅแจแแแแก แแฆแแแชแแแแแแก แฌแงแแ แ, แฉแแแแแแแก แแก แแก แแแแ แแแ, แกแแแแช แแแกแแแแแแแแแ แกแแฅแแแแแแ แแแแแแแกแแแฃแแ. แแแแก แแแฐแงแแแแ แแฅแจแแแแก แแแแแ แแแฎแแกแแแแแแ. แฉแแแ แแแชแแ, แ แแ แแฎแแแ แแแแแแก แจแแฅแแแแกแแก แฃแแแ แแแแแฆแแ แแแแแแก แแฆแฌแแ แ, แแแแขแแแแช แแแก แแ แแแกแจแ แแแแฃแแแแแแ, แ แแแแ แช แคแฃแแฅแชแแแก แขแแแก - แแแ แฃแแแ แแแแแ แฃแแแก แแแแแฅแขแ, แ แแแแแจแแช แแฅแแแแ แกแขแ แแแแแก แขแแแแก แคแ แแคแแ แแ description
. แแฃ แแฅแจแแแแก แแ แแแแแ แแ แแแญแแ แแแแ, แแแก แฃแแ แแแแ แแแแแแขแแแแแ, แ แแแแ แช แแก getItems
-แแก แจแแแแฎแแแแแจแแ.
แแฅแจแแแแ แฃแแแ แแแแแ แแก แ แแแแฃแกแแ แ แแ แแคแแฅแขแแแ. แ แแแแฃแกแแ แ แแแแแแ แกแแแแแแก แฃแจแฃแแแแ แจแแกแแชแแแแแแ, แฎแแแ แแคแแฅแขแแแ API-แกแแแ แแแกแแแแแจแแ แแแแแ. API-แกแแแ แฃแ แแแแ แแแแแจแ แฉแแแ แฎแจแแ แแ แแ แ แขแแแแก แแฅแจแแแ แแแแฅแแก: แฌแแ แแแขแแแแก แแ แแ แแ แแก แแฅแจแแแแแ. แแแแแแฃแแ แแแแฎแแ แแแแแก แแฅแจแแแแก แกแแคแฃแซแแแแแ, แ แแแแแแช API-แกแแแ แแแแจแแ แก แกแแญแแ แแแแก, แแคแแฅแขแแแ แกแแแแกแฃแฎแแ แแแกแชแแแแ แแ แแฅแจแแแแแก. แแแแแแแก แชแแแแ แคแแแแจแ แแแแฌแแ แแ แแฅแจแแแแแ:
store/actions/todo-api.actions.ts
import { createAction, props } from "@ngrx/store";
import { Item } from "src/app/item.model";
export const getItemsSuccessful = createAction(
"[Todo Api] Get Items Successful",
props<{ items: Item[] }>()
);
export const getItemsFailed = createAction(
"[Todo Api] Get Items Failed",
props<{ error: string }>()
);
export const addItemSuccessful = createAction(
"[Todo Api] Add Item Successful",
props<{ item: Item }>()
);
export const addItemFailed = createAction(
"[Todo Api] Add Item Failed",
props<{ error: string }>()
);
export const updateItemSuccessful = createAction(
"[Todo Api] Update Item Successful",
props<{ item: Item }>()
);
export const updateItemFailed = createAction(
"[Todo Api] Update Item Failed",
props<{ error: string }>()
);
export const deleteItemSuccessful = createAction(
"[Todo Api] Delete Item Successful",
props<{ id: number }>()
);
export const deleteItemFailed = createAction(
"[Todo Api] Delete Item Failed",
props<{ error: string }>()
);
แกแแแแแแแแกแแแแก แแแแแ แคแแแแแ แจแ index.ts แจแแแฅแแแแ, แกแแแแแแแช แแแแแแฅแกแแแ แขแแแ แงแแแแ แแฅแจแแแก, แ แแแแแแช แแฅแจแแแแแแก แแ แแ แคแแแแแ แจแ แแฅแแแแ แแแแแกแคแแแกแแ (Namespace), TodoActions แฎแแแ แแแแ แแจแ TodoApiActions. แแกแ แแแแแฅแชแแแแ แกแแแ แแก แงแแแแ แแแแแแแขแแกแแแแก.
store/actions/index.ts
export * as TodoActions from "./todo.actions";
export * as TodoApiActions from "./todo-api.actions";
แแแแแแแแแ, แแฎแแแ แแแแแแก แจแแฅแแแแก แแฅแจแแแแ (addItem
) แฃแจแฃแแแแ แกแแแแแจแ แแฎแแแแ แแก แฃแแแ แแกแแฎแแก, แ แแ แแแแแแแแ แแแแก API-แกแแแ แแแกแฃแฎแแก แแแแแแแแ. แแแแก แจแแแแแ, แแคแแฅแขแแแแ แฃแแแ แแแแคแแฅแกแแ แแ แแก แแฅแจแแแ, แแแแฎแแแแ แแแแแแแแแ แกแแ แแแ แแ แแ แแแกแชแแ แแฎแแแ แแฅแจแแแ addItemSuccessful
, แ แแแแแแก prop-แกแแช แ แแแแฃแกแแ แ แกแแแแแจแ แแแแแแแแกแแแก. แฏแแ แแแแแแแแก แแฆแแแแก แแฅแจแแแกแ แแ แแแแแแแแแก แกแแแแแก แแแแฎแแแแ. แจแแแฅแแแแ แฉแแแแ แแแแแแแชแแแก แกแแแแแแก แขแแแ, แ แแแแแแแช แ แแแแฃแกแแ แ แแฎแแแแซแฆแแแแแแแแก:
store/state/todo.state.ts
import { Item } from "src/app/item.model";
export interface TodoState {
items: Item[];
loading: boolean;
error: string;
}
แกแแแแแจแ แแแแแแ แแแแแแแแก แกแแ, แฉแแขแแแ แแแ แแแแแแแแ แแแแก แแฃ แแ แ แแ แแ แกแแแแแก แแฃ แแ แ แแ แแ แ. แแกแแช แแแแแแฅแกแแแ แขแแ index.ts-แแแ.
store/state/index.ts
export * from "./todo.state";
แแฎแแ แจแแแฅแแแแ แ แแแแฃแกแแ แ:
store/state/reducers/todo.reducer.ts
import { createReducer, on } from "@ngrx/store";
import { TodoActions } from "../actions";
import { TodoState } from "../state";
const initialState: TodoState = {
items: [],
loading: false,
error: "",
};
export const todoReducer = createReducer(
initialState,
// Get Items
on(TodoActions.getItems, (state) => ({ ...state, loading: true }))
on(TodoApiActions.getItemsSuccessful, (state, { items }) => ({
...state,
items: items,
loading: false,
})),
on(TodoApiActions.getItemsFailed, (state, { error }) => ({
...state,
error: error,
loading: false,
})),
);
แ แแแแฃแกแแ แ แแฅแแแแแ createReducer
แคแฃแแฅแชแแแ, แ แแแแแแช แแแ แแแ แแ แแฃแแแแขแแ แแแ แแแแแแ แกแแแแแก แแฆแแแก. แแแ แแแแแแ แกแแแแแก แฉแแแ แแแแชแแแแแแแชแแแก แแฃแแแแแแ แแแแแ แคแแแแจแ. แแแแแแแชแแ แแแ แแแแแแ แแแแแแแ แแแแแจแ แจแแแชแแแก แแแแแแแแก แชแแ แแแ แกแแแก, แฉแแขแแแ แแแแก แฃแแ แงแแคแแแ แแแแจแแแแแแแแ แแ แแ แแ แก, แ แแแแ แช แชแแ แแแ แกแขแ แแแแก.
แจแแแแแ แแ แแฃแแแแขแแแแ แ แแแแฃแกแแ แ แแฆแแแก on
แคแฃแแฅแชแแแแก. on
แคแฃแแฅแชแแแแ แแแแกแแแฆแแ แแแก แแแแแแฃแแ แแฅแจแแแแก แกแแคแฃแซแแแแแ (แแแ แแแแ แแ แแฃแแแแขแ) แ แแแแ แฃแแแ แจแแแชแแแแแก แกแแแแแ (แแแแ แ แแ แแฃแแแแขแ แฅแแแแแฅแแก แคแแ แแแ).
แฅแแแแแฅ แคแฃแแฅแชแแแจแ แแแแ แฃแแแแ แกแแแแแก แแแกแแ แแแแแ แคแแ แแแ, แ แแแ แงแแแแแแ แแฎแแแแ แแฅแจแแแแ แจแแแแแ แฉแฃแแแก แแ แแ แฌแแจแแแแก แฌแแแ แกแแแแแ. แแแก แจแแแแแ แแแแแฅแขแจแ แฉแแแแแแแก แกแแกแฃแ แแแ แกแแแแแแก แแแฌแแแแแก แแแแจแแแแแแแแก แจแแแฃแชแแแแ. แ แแชแ แแแแฎแแแ แแแแแ แแแแแแแแก แแแฆแแแแก แแฅแจแแแก แแแแแฎแแ แชแแแแแแก, แฉแแแ แฃแแแ แแแแแแแฉแแแแ แแแแแแแแแก แแแแแแแ แแแแ, แแแจแแกแแแแแ loading-แก แแแแฎแแแ แญแแจแแแ แแขแก. แแแแก แกแแคแฃแซแแแแแ แฉแแแ แฃแแแ แแแแแแแฉแแแแ แแแ-แแแแ แแแ แฉแแขแแแ แแแแก แกแแแแแ แ. แแแแแแแแก แฌแแ แแแขแแแแ แแแฆแแแแก แจแแแแฎแแแแแจแ, แฉแแแ แฃแแแ แแ แแฅแจแแแแก props-แแแแ แแแฆแแแฃแแ แแฎแแแ แแแแแ แกแแแแแจแ แแแแแแแแแกแแ, แฎแแแ loading แแแแฎแแแแ แแชแแแ แ.
แแแแ แแ แ แแแแ แแแแฆแแ loading แคแ แแคแแ แแ แแ items แกแแแแแแแแ? แกแแแแฅแขแแ แแแแก แกแแจแฃแแแแแแ! แแแแ แแ แฏแแ แฉแแแแ แ แแแแฃแกแแ แ แแแแแ แแแแกแขแ แแ แแ แแแแฃแแจแ, แ แแแ แแแแฃแแแ แแ แแก แแแแคแแฅแกแแ แแก.
store/state/reducers/index.ts
export * from "./todo.reducer";
app.module.ts
// ... other imports
import { StoreModule } from "@ngrx/store";
import { todoReducer } from "./store/reducers";
import { StoreDevtoolsModule } from "@ngrx/store-devtools";
@NgModule({
declarations: [AppComponent, ItemComponent, InputComponent],
imports: [
// ... other imports
StoreModule.forRoot({ todo: todoReducer }),
],
providers: [],
bootstrap: [AppComponent],
})
export class AppModule {}
แจแแแแจแแแ: แแฃ แแแแแแแชแแแจแ แกแฎแแ แแแแแ แแขแฃแแ แแแแฃแแแแแช แแแแฅแแก, app.module.ts-แจแ forRoot แคแฃแแฅแชแแ แแแ แฉแแแ แชแแ แแแแ, แฎแแแ แกแฎแแ feature แแแแฃแแแแจแ, แแแแแแแแแ แแฃ แแแแฅแแก แชแแแแ notes แแ todo feature-แแแ, แแแแฅแแแแ
StoreModule.forFeature({ notes: notesreducer })
แแStoreModule.forFeature({ todo: todoreducer })
. แฃแแฏแแแแกแแ, แ แแ แงแแแแ feature module-แก แแแแแกแ แกแแแ แ แฐแฅแแแแแก.
แฉแแแ แแแแฃแแแ แก แแแฃแแแแแแ, แ แแ แแแ แแแแกแขแ แแ แแแ แ แแแแฃแกแแ แก, แ แแแแแแช แแกแแชแแ แแแฃแแ แแฅแแแแ แกแแฎแแแแแ โtodoโ. แแก แฃแแแแแกแแแแแ แแแแแญแแ แแแแ แกแแแแฅแขแแ แแแแก แจแแกแแฅแแแแแแ.
store/state/selectors/todo.selectors.ts
import { createFeatureSelector, createSelector } from "@ngrx/store";
import { TodoState } from "../state";
export const selectTodo = createFeatureSelector<TodoState>("todo");
export const selectLoading = createSelector(
selectTodo,
(state: TodoState) => state.loading
);
export const selectItems = createSelector(
selectTodo,
(state: TodoState) => state.items
);
export const selectError = createSelector(
selectTodo,
(state: TodoState) => state.error
);
createFeatureSelector
-แแก แกแแจแฃแแแแแแ แฉแแแ แกแแแแฅแขแแ แก แแฅแแแแ แแแแแ แแขแฃแแ feature-แแกแแแแก. แฉแแแ แ แแแแฃแกแแ แก แแแแฃแแจแ แแกแแชแแแชแแ แแแแฃแแแแแ โtodoโ แกแแฎแแแแแ, แแแแขแแ แแ แแฃแแแแขแแ แกแฌแแ แแ แแ แกแแฎแแแก แแฌแแ แ. แกแแแ แ แกแแแแแแกแแแ แแแคแแ แแแชแแแก แแแแก แกแแคแฃแซแแแแแ แแแฆแแแก แแ แแแแแแแ แฃแแแแก แกแขแ แแแแก แคแแ แแแ. แจแแแแแ แกแแแแแแก แแแแแแฃแแ แแแฌแแแแกแแแแก แชแแแแ แแฅแแแแ แกแแแแฅแขแแ แแแก createSelector
แคแฃแแฅแชแแแ, แ แแแแแแช แแ feature แกแแแแฅแขแแ แแกแแแ แแฆแแแแ แแแก แแแแแ แแขแฃแ แแแฌแแแก. แแแแแแแแแฃแ แแ แกแแแแฅแขแแ แแแ select-แแ แแฌแงแแแ.
แแฎแแ แแแแแแแงแแแแ selectLoading app.component-แจแ แแ แแแแกแแแแแแ, แแแแชแแ แแฅแจแแแ. แงแแแแแคแแ แ แแแแแแขแ แฌแแแจแแแแ.
app.component.ts
/// ... other imports
import { Store } from "@ngrx/store";
import { TodoActions } from "./store/actions";
import { TodoSelectors } from "./store/selectors";
// ...
export class AppComponent implements OnInit {
items$ = this.store.select(TodoSelectors.selectItems);
loading$ = this.store.select(TodoSelectors.selectLoading);
error$ = this.store.select(TodoSelectors.selectError);
constructor(private store: Store) {}
ngOnInit() {
this.store.dispatch(TodoActions.getItems());
}
}
แฉแแแ แแแแกแขแ แฃแฅแขแแ แจแ แแแแแแแฏแแฅแแแ Store, แ แแแแแแช แฌแแแแแแก แแแแซแแแแก แกแแแแแแก แกแแแแฅแขแแ แแแกแ แแ แแฅแจแแแแก แแแจแแแแแก แคแฃแแฅแชแแแแแ. แกแแแแฅแขแแ แแแก แแแแแฎแแแ แคแ แแคแแ แแแแแแ, แ แแแแแแแช แแแแแแแชแแฃแ แแ $-แแ แแแแแแแแแ, แ แแแแแ แแกแแแ observable-แแแก แฌแแ แแแแแแแแแ.
แ แแชแ แแแแแแแชแแ แแขแแแ แแแแ, แแก แฃแแแ แแแจแแแแก แแแแก, แ แแ แแแแฎแแแ แแแแแก แแแแแแแแก แแแฆแแแ แกแฃแ แก, แแแจแแกแแแแแ แฉแแแ แฃแแแ แกแแแ แแก แกแแจแฃแแแแแแ getItems
แแฅแจแแแก แแแแฃแซแแฎแแ.
แแแแคแแแแแจแ แจแแแแแซแแแ observable-แแแก แแแแฃแกแแแแแ ngIf
แแแ แแฅแขแแแจแ, async แคแแแคแแก แกแแจแฃแแแแแแ. แแก แคแแแคแ แแแขแแแแขแฃแ แแ แแแแกแฃแแกแฅแ แแแแแแก แแ observable-แก แแ แกแแญแแ แแแแแก แจแแแแฎแแแแแจแ แกแฃแแกแฅแ แแแแก แแแแฃแฅแแแแก แแแแแแแช (ts-แจแ แแแแก แฎแแแแ แฌแแ แแก แคแแแคแ แแแแแแแแแ แฏแแแแ!):
app.component.html
<div class="container">
<app-input></app-input>
<ng-container *ngIf="error$ | async as error">
<h2 class="error"></h2>
</ng-container>
<ng-container *ngIf="items$ | async as items">
<app-item *ngFor="let item of items" [item]="item"></app-item>
</ng-container>
<ng-container *ngIf="loading$ | async">
<div class="spinner-container">
<img src="../assets/tail-spin.svg" alt="loading spinner" />
</div>
</ng-container>
</div>
แ แแชแ observable แ แแแแ แแแกแแฆแแ (truethy) แแแแจแแแแแแแแก แแแแฆแแแก, แแแแแแแขแ, แ แแแแแแแช แแแ แแฅแขแแแแ แแแแแแแกแแแฃแแ, แแแแแฉแแแแแ. แแ แแ แแก แจแแแแฎแแแแแจแ, แแแแแแแแแ, แจแแแแแซแแแ as error
-แแก แกแแจแฃแแแแแแ แแ แกแแแแแแ แแแแจแแแแแแแแก แฉแแแฌแแแแ, แแ แแแแคแแแแแจแ แแแแแแกแแฎแแ, แแฃแแ แ แแแแ แฎแแ แแแแ แแแแแแฉแแแ. แแแแแ แฎแแแแ items-แแกแ แแ loading-แแก แจแแแแฎแแแแแจแ.
แแ แแฃแแแ แจแ แแฎแแ แฉแแขแแแ แแแแก แกแแแแแ แ แฃแแแ แแแแแฉแแแแก. Redux Devtools-แก แแฃ แจแแแฎแแแแแ, แแแแฎแแแ, แ แแ แแแแชแ แแฅแจแแแ โ[Todo Page] Get Itemsโ, แ แแแแแแแช แกแแแแแจแ loading-แแก แแแแจแแแแแแแ แจแแชแแแแ, แแก แแ async แคแแแคแแก แกแแจแฃแแแแแแ แแแขแแแแขแฃแ แแ แแแกแแฎแ แฉแแแแก แแแแแแแชแแแจแ!
Effects
แแจแแแ แ แแ แแแแแแ แแแแฅแแก: แแแแแแแ แฏแแ แแ แแแแแฉแแแแแ, แ แแแแแ แกแแฌแงแแก แกแแแแแจแ แแก แชแแ แแแแแ, แฉแแแ แแ API-แกแแแแก แแ แแแแแแซแแฎแแแแ, แ แแ แแกแแแ แแแแแฆแ. แแแจ, แจแแแฅแแแแ แแคแแฅแขแแแ! แฏแแ ItemsService-แจแ tap
แแแแ แแขแแ แแแ แแ แแแแแแขแ แชแแแแแแแ แแแแแจแแ แแ. แแกแแแ แแฆแแ แแแแแญแแ แแแแ.
items.service.ts
import { HttpClient } from "@angular/common/http";
import { Injectable } from "@angular/core";
import { map } from "rxjs";
import { environment } from "src/environments/environment";
import { Item } from "./item.model";
@Injectable({ providedIn: "root" })
export class ItemsService {
baseUrl = environment.baseUrl;
constructor(private httpClient: HttpClient) {}
getItems() {
return this.httpClient.get<Item[]>(this.baseUrl);
}
addItem(newItemDesc: string) {
const newItem = {
description: newItemDesc,
done: false,
};
return this.httpClient.post<Item>(this.baseUrl, newItem);
}
deleteItem(id: number) {
return this.httpClient.delete(this.baseUrl + id).pipe(
map(() => {
return id;
})
);
}
updateItem(item: Item) {
return this.httpClient.patch<Item>(this.baseUrl + item.id, {
description: item.description,
done: item.done,
});
}
}
แแฎแแ แแ แจแแแฅแแแแ แแคแแฅแขแแแ:
store/state/effects/todo.effects.ts
import { HttpErrorResponse } from "@angular/common/http";
import { Injectable } from "@angular/core";
import { Actions, createEffect, ofType } from "@ngrx/effects";
import { catchError, map, mergeMap, of } from "rxjs";
import { ItemsService } from "src/app/items.service";
import { TodoActions, TodoApiActions } from "../actions";
@Injectable()
export class TodoEffects {
getItems$ = createEffect(() => {
return this.actions$.pipe(
ofType(TodoActions.getItems),
mergeMap(() =>
this.itemsService.getItems().pipe(
map((items) => TodoApiActions.getItemsSuccessful({ items })),
catchError((err: HttpErrorResponse) =>
of(
TodoApiActions.getItemsFailed({
error: `Failed to get items!: Server responded with: ${err.message}`,
})
)
)
)
)
);
});
constructor(private actions$: Actions, private itemsService: ItemsService) {}
}
แแ แจแแแแจแแแแแ, RxJs แแฅแแแแ แแแแแแแ แแ! แฉแแแ แแฅแแแแ แแคแแฅแขแแแแก แแแแกแก, แ แแแแแแแช แฃแแแ แแแแแแแงแแแแ @injectable()
แแแแแ แแขแแ แ (แ แแแแแ แแก แกแแ แแแกแแแแ แแฃแจแแแแก). แแแแกแจแ แแแแแกแแแฆแแ แแแ แแคแแฅแขแแแก, แ แแแแแแแช แคแแฅแขแแแ แแแแ subscription-แแแแ. แแกแแแ createEffect
แคแฃแแฅแชแแแ แแฅแแแแแ. แฅแแแแแฅแจแ แฉแแแ แแแกแฃแแกแฅแ แแแแแแ แแฅแจแแแแแแก แกแขแ แแแก, แ แแแแแกแแช แกแแแ แ แแแแฌแแแแก Actions-แแก แกแแฎแแ. แฉแแแ แกแขแ แแแ แฃแแแ แแแแคแแแขแ แแ, แ แแแแแ getItems$
แแคแแฅแขแแ แแฎแแแแ แแ แแ แแฅแจแแแแ แฃแแแ แแแแฎแแแแแก แ แแแแแ แแแ - TodoActions.getItems
. pipe
แแแแ แแขแแ แจแ แกแฌแแ แแ แแแแขแแ แแแงแแแแแ ofType
แแแแ แแขแแ แก. แจแแแแแ, mergeMap
-แแก แกแแจแฃแแแแแแ แฉแแแ แแแแแแ แฃแแแแ แกแแ แแแกแแก API-แกแแแ แแแซแแฎแแแแก, แกแแแแช แฉแแแ แแแแแแ, แ แแ map
แแแแ แแขแแ แแ แแแแแแฆแแ แกแแ แแแ แแแแ แแแกแฃแแ แแแกแฃแฎแ (แแแแแแแ) แแ แแก แฉแแแแ TodoApiActions-แแก แแฅแจแแแก แแแแแแชแแ, แ แแแแแกแแช observable
-แแก แคแแ แแแ แแแแ แฃแแแแ. catchError
-แก แฉแแแ แกแแ แแแกแแ แแแซแแฎแแแฃแ pipe
แแแแ แแขแแ แจแ map
-แแก แจแแแแแ แแแงแแแแแ, แ แแแ แฌแแ แฃแแแขแแแแแแแแก แจแแแแฎแแแแแจแ แแฆแแ แแชแฎแแ, แ แ แกแแฎแแก แแ แแ แ แแแแแแแ แฃแแ แกแแ แแแ แแ. แแก แแ แแ แ HttpErrorResponse-แแก แขแแแแกแแ แแ แแ แแแฅแขแแก แจแแแแฎแแแแแจแ. แแ แแ แแ แแก แแแกแแฏแก แฉแแแ แแแแแแแงแแแแแ แแฅแจแแแจแ แแ แแ แแก แขแแฅแกแขแแก แจแแกแแฅแแแแแแ, แ แแแแแกแแช แฉแแแ of
แแแแ แแขแแ แจแ แแแขแแ แแแ, แ แแแแแ catchError แแแแแแ observable-แก แแ แแแ แฃแแแแก, แ แแช แแคแแฅแขแแกแแแแกแแ แกแแญแแ แ. of
แแแแ แแขแแ แ แกแฌแแ แแแแช observable-แจแ แจแแคแฃแแฃแ แแฅแจแแแก แแแแแแแ แฃแแแแก.
store/state/effects/index.ts
export * from "./todo.effects";
แแฎแแ แแแแแ แแแแกแขแ แแ แแ แฉแแแแ แแคแแฅแขแแแ แแแแฃแแจแ:
app.module.ts
/// ... other imports
import { StoreModule } from "@ngrx/store";
import { todoReducer } from "./store/reducers";
import { StoreDevtoolsModule } from "@ngrx/store-devtools";
import { EffectsModule } from "@ngrx/effects";
import { TodoEffects } from "./store/effects";
@NgModule({
// ...
imports: [
// ...
StoreModule.forRoot({ todo: todoReducer }),
EffectsModule.forRoot([TodoEffects]),
// ...
],
// ...
})
export class AppModule {}
แจแแแแจแแแ: แแแแแแแแกแแ แแคแแฅแขแ Array-แจแ, แ แแแแแ แแคแแฅแขแ แแ แแแ แแแขแ แจแแแซแแแแ แแแฅแแแแแก.
แแ แแฃแแแ แจแ แจแแแแญแงแแขแแ. แฉแแแแ แแแแแแแ แ แแแแ แช แแฅแแ แแแแแฉแแแ! Redux-แแก แแแแแฃแแแจแ แแ แแฎแแแแแ, แ แแ โ[Todo Page] Get Itemsโ-แก แแแฐแงแแ โ[Todo Api] Get Items Successfulโ, แ แแแแแแแช แกแแแแแจแ แแแแแแแแขแ แแฎแแแ แแแแแแแ, แฎแแแ loading แแแแแชแแแแ false-แแ (แ แแแแ แช แฉแแแ แแก แ แแแแฃแกแแ แจแ แแแแฃแแแแแ). แแฎแแ แแแแแแแชแแแก แกแฎแแ แคแฃแแฅแชแแแแก แแแแฎแแแแ, แแแ แฃแแแแแกแ แแ แแฅแขแแแแก แแแขแแ แแแแก แแแแงแแแ.
แฃแแแแแกแ แแแขแแ แแแแ
แซแแ แแแแแ แแแแแแ, แ แแแแแแช แกแแแ แก แแฎแแแ แฃแแแ แแงแแก แแแแแแแกแแแฃแแ แแ แ แแแแขแแแแแ แแแแแแแแแขแจแ, แแแก แจแแแแแ แแ แกแแแฃแแ แแแขแแ แ แแแแแแแแแขแแแ แแ แฃแแ แแแแ แแแแแชแแแแแก แแฆแแแแ แแแแ แแแแแแแแแขแแแแ, แแแก แแแแคแแแแแจแ แแแแแแแแกแแแแ แแ แฃแแ แแแแ แแแแแแแแก แแแแแแแแแ. แแกแแ แแ แแแแแจแแ แแ แกแแ แแแกแแแแแ แแแแแแจแแ แแแฃแแ แแแแแแ input แแแแแแแแแขแแแแ แแ item แแแแแแแแแขแแแแ.
input/input.component.ts
import { Component, EventEmitter, Output } from "@angular/core";
@Component({
selector: "app-input",
templateUrl: "./input.component.html",
styleUrls: ["./input.component.css"],
})
export class InputComponent {
@Output() newItem = new EventEmitter();
onNewItem(inputElement: HTMLInputElement) {
const newItemDesc = inputElement.value;
if (newItemDesc) {
this.newItem.emit(newItemDesc);
inputElement.value = "";
}
}
}
item/item.component.ts
import { Component, EventEmitter, Input, Output } from "@angular/core";
import { Item } from "../item.model";
@Component({
selector: "app-item",
templateUrl: "./item.component.html",
styleUrls: ["./item.component.css"],
})
export class ItemComponent {
@Input() item: Item;
@Output() delete = new EventEmitter<number>();
@Output() updateItem = new EventEmitter<Item>();
onDeleteItem() {
this.delete.emit(this.item.id);
}
onItemDone() {
this.updateItem.emit({ ...this.item, done: !this.item.done });
}
}
แแแแขแแแแแ แแแแแแแแแขแจแ, แแแฃ app.component.html-แจแ, แแแแฃแกแแแแแ แแ แแแแแแแแแขแแแแก แแแแแแแแก:
app.component.html
<div class="container">
<app-input (newItem)="onNewItem($event)"></app-input>
<ng-container *ngIf="error$ | async as error">
<h2 class="error"></h2>
</ng-container>
<ng-container *ngIf="items$ | async as items">
<app-item
*ngFor="let item of items"
[item]="item"
(delete)="onDelete($event)"
(updateItem)="onUpdateItem($event)"
></app-item>
</ng-container>
<ng-container *ngIf="loading$ | async">
<div class="spinner-container">
<img src="../assets/tail-spin.svg" alt="loading spinner" />
</div>
</ng-container>
</div>
แแ แกแแแแแแแ แแฅแจแแแแแ แแแแชแแ แแแแแแแแแก แแแฎแแแแแ, แ แแแแแแกแแช แกแแแแแแแ prop-แแแก แแแแแขแแแ:
app.component.ts
import { Component, OnInit } from "@angular/core";
import { Store } from "@ngrx/store";
import { Item } from "./item.model";
import { TodoActions } from "./store/actions";
import { TodoSelectors } from "./store/selectors";
@Component({
selector: "app-root",
templateUrl: "./app.component.html",
styleUrls: ["./app.component.css"],
})
export class AppComponent implements OnInit {
items$ = this.store.select(TodoSelectors.selectItems);
loading$ = this.store.select(TodoSelectors.selectLoading);
error$ = this.store.select(TodoSelectors.selectError);
constructor(private store: Store) {}
ngOnInit() {
this.store.dispatch(TodoActions.getItems());
}
onNewItem(description: string) {
this.store.dispatch(TodoActions.addItem({ description }));
}
onDelete(id: number) {
this.store.dispatch(TodoActions.deleteItem({ id }));
}
onUpdateItem(item: Item) {
this.store.dispatch(TodoActions.updateItem({ item }));
}
}
แแแแแแแชแแแก แแแแแ แฉแแแ แคแฃแแฅแชแแแแ NgRx-แแ
แแฎแแ แ แแแแฃแกแแ แจแ แแแแฌแแ แแ แ แ แฃแแแ แแแฎแแแก แแแแแ แฉแแแ แแฅแจแแแแแแก แจแแแแฎแแแแแจแ:
store/reducers/todo.reducers.ts
import { createReducer, on } from "@ngrx/store";
import { TodoActions, TodoApiActions } from "../actions";
import { TodoState } from "../state";
import { TodoUtils } from "../util/todo.util";
const initialState: TodoState = {
items: [],
loading: false,
error: "",
};
export const todoReducer = createReducer(
initialState,
// Get Items
on(TodoActions.getItems, (state) => ({ ...state, loading: true })),
on(TodoApiActions.getItemsSuccessful, (state, { items }) => ({
...state,
items: items,
loading: false,
})),
on(TodoApiActions.getItemsFailed, (state, { error }) => ({
...state,
error: error,
loading: false,
})),
// Add Item
on(TodoActions.addItem, (state) => ({ ...state, loading: true })),
on(TodoApiActions.addItemSuccessful, (state, { item }) => ({
...state,
items: [item, ...state.items],
loading: false,
})),
on(TodoApiActions.addItemFailed, (state, { error }) => ({
...state,
error: error,
loading: false,
})),
// Delete Item
on(TodoActions.deleteItem, (state) => ({ ...state, loading: true })),
on(TodoApiActions.deleteItemSuccessful, (state, { id }) => ({
...state,
items: TodoUtils.removeItem(state.items, id),
loading: false,
})),
on(TodoApiActions.deleteItemFailed, (state, { error }) => ({
...state,
error: error,
loading: false,
})),
// Update Item
on(TodoActions.updateItem, (state) => ({ ...state, loading: true })),
on(TodoApiActions.updateItemSuccessful, (state, { item }) => ({
...state,
items: state.items.map((i) => {
if (i.id === item.id) {
return item;
} else {
return i;
}
}),
loading: false,
})),
on(TodoApiActions.updateItemFailed, (state, { error }) => ({
...state,
error: error,
loading: false,
}))
);
แแแแแแก แฌแแจแแแก แฌแแ แแแขแแแฃแแแ แแแแแแแ แแแแก แจแแแแฎแแแแแจแ แแแแแแก แแแแกแแจแแแแแ TodoUtils-แจแ แจแแฅแแแแ แคแฃแแฅแชแแแก แแแงแแแแแ, แ แแแ แ แแแแฃแกแแ แ แ แแฃแแ แฌแแกแแแแแฎแ แแ แแแฎแแแก:
store/util/todo.utils.ts
import { Item } from "src/app/item.model";
export class TodoUtils {
public static removeItem(items: Item[], id: number) {
const result = [...items];
const itemindex = result.findIndex((i) => i.id === id);
result.splice(itemindex, 1);
return result;
}
}
แ แ แแฅแแ แฃแแแ, แแก แกแแแ แแฎแแแ แแฅแจแแแ แแแแแแแแแขแจแ แฃแแ แแแแ แฉแแขแแแ แแแแก แกแแแแแ แก แแแแแแฉแแแก แแแแแแแชแแแจแ, แ แแแแแ แแแแแแแก แแคแแฅแขแแแ แฏแแ แแ แแแแแแฌแแ แแ. แแกแ แฃแแแ แแแแแแงแฃแ แแแแแแก แแคแแฅแขแแแแก แแแแแแแ แแแแ:
store/effects/todo.effects.ts
import { HttpErrorResponse } from "@angular/common/http";
import { Injectable } from "@angular/core";
import { Actions, createEffect, ofType } from "@ngrx/effects";
import { catchError, map, mergeMap, of } from "rxjs";
import { ItemsService } from "src/app/items.service";
import { TodoActions, TodoApiActions } from "../actions";
@Injectable()
export class TodoEffects {
getItems$ = createEffect(() => {
return this.actions$.pipe(
ofType(TodoActions.getItems),
mergeMap(() =>
this.itemsService.getItems().pipe(
map((items) => TodoApiActions.getItemsSuccessful({ items })),
catchError((err: HttpErrorResponse) =>
of(
TodoApiActions.getItemsFailed({
error: `Failed to get items!: Server responded with: ${err.message}`,
})
)
)
)
)
);
});
addItem$ = createEffect(() => {
return this.actions$.pipe(
ofType(TodoActions.addItem),
mergeMap(({ description }) =>
this.itemsService.addItem(description).pipe(
map((item) => TodoApiActions.addItemSuccessful({ item })),
catchError((err: HttpErrorResponse) =>
of(
TodoApiActions.getItemsFailed({
error: `Failed to add item!: Server responded with: ${err.message}`,
})
)
)
)
)
);
});
deleteItem$ = createEffect(() => {
return this.actions$.pipe(
ofType(TodoActions.deleteItem),
mergeMap(({ id }) =>
this.itemsService.deleteItem(id).pipe(
map((id) => TodoApiActions.deleteItemSuccessful({ id })),
catchError((err: HttpErrorResponse) =>
of(
TodoApiActions.getItemsFailed({
error: `Failed to delete item!: Server responded with: ${err.message}`,
})
)
)
)
)
);
});
updateItem$ = createEffect(() => {
return this.actions$.pipe(
ofType(TodoActions.updateItem),
mergeMap(({ item }) =>
this.itemsService.updateItem(item).pipe(
map((item) => TodoApiActions.updateItemSuccessful({ item })),
catchError((err: HttpErrorResponse) =>
of(
TodoApiActions.getItemsFailed({
error: `Failed to update item!: Server responded with: ${err.message}`,
})
)
)
)
)
);
});
constructor(private actions$: Actions, private itemsService: ItemsService) {}
}
แแแแแแแ แแแ, แ แแ แแแแแ แฉแแ แแคแแฅแขแแแจแ mergeMap
-แแ แแแฏแแ แแ แแแฆแแแ (แแแกแขแ แฃแฅแขแฃแ แแแแชแแแก แกแแจแฃแแแแแแ) แแฅแจแแแแแแก prop-แแแก, แ แแแแแแกแแช แกแแ แแแกแก แแแฌแแแแ.
แฉแแแแ แแแแแแแชแแ แแฎแแ แกแ แฃแแคแแกแแแแแ แฃแแแ แแฃแจแแแแแแก NgRx-แแ. แแ แแ แจแแฎแแแแแ แแ แแกแแญแแ แแ แแแแ แ แแแแ แแฌแแ แแ แแ แแแแฅแแก แจแแแแแแแแ แแแแแ แแแแแแแงแแแแ, แแแแ แแ แ แแชแ แแแ แแ แ แแฃแ แแแแแแแชแแแแ แแแฃแจแแแแ, NgRx-แแก แกแแจแฃแแแแแแ แแฃแกแขแแ แแแชแแ แกแแ แ แ แฃแแแ แแแฎแแแก แแ แ แแแแ , แ แแช แแแแแแแแแแแขแแก แแ แแชแแกแก แซแแแแแ แแแแ แขแแแแแก. แแแ แแแแแซแฃแแแแก, แ แแ แกแแฃแแแแแกแ แแแขแแ แแแแก แแแแงแแแ, แ แแช แแแแ แแแฃแแแแแแกแฌแแแแแแ แแแแแก แขแแแแแแก แแแแแ แแแแแก.
แแ แแคแแฅแ แแ, แ แแ NgRx-แก แแ แแ แฌแแแแแฎแแแ แแแแฃแคแแแแแ. แกแแญแแ แแแแแก แจแแแแฎแแแแแจแ แ แแแแแแแแแฏแแ แแแแแแแแแฎแแ แแก แแแกแแแ, แแแแชแแแแ แแคแแชแแแแฃแ แแแแฃแแแแขแแชแแแแก แแ, แ แ แแฅแแ แฃแแแ, แแฅแแแแแ แกแชแแแแ แแแกแ แแแแแงแแแแแ.
แฌแแ แแแขแแแแแ!