Angular State Management (NGXS) Code

2018. 9. 22. 23:04

오늘은 지난 글에서 소개했던 ngxs의 코드를 살펴보겠습니다.


아래와 같은 순서로 만들어 가게 되는데요.


1. Action 추가 (소비 내역 추가)

2. State 추가 (하루 소비 내역)

3. Select 추가 (component에서 하루 소비 내역 조회)


1. Action 추가


action은 데이터를 변경하는 동작을 말합니다.

소비 내역을 추가하는 action을 정의하였습니다.

(저는 가계부를 만드는 개인 프로젝트 진행중입니다.)

import { Consumption } from "../domain/consumption";

export class AddConsumption {
    static readonly type = '[Budget Page] Add Consumption';
    constructor(public consumption: Consumption) {}
}

지난 번 생성한 Consumption 도메인을 활용합니다.


type에는 어떠한 action인지 설명을 적어줍니다.

ngxs 공식 페이지에서는 아래와 같은 규칙을 권장합니다.

- 명령이 수행되는 맥락 (ex: [User API],[Product Page])

- 행위를 설명하는 동사 (ex: Get, Add, Delete)

- 행위의 대상 Entity (ex: User, Product)


constructor는 추가할 consumption을 인자로 받습니다.


즉, 설명과 Action이 수행될 metadata를 정의해주는 것입니다.


2. State 추가


State의 이름과 기본값, action의 실제 동작을 정의합니다.

ngxs 코드의 가장 핵심 부분이라고 볼 수 있습니다.


State는 @State라는 annotation을 사용하여 정의합니다.

import { Action, State, StateContext } from '@ngxs/store';
import { DailyExpense } from '../domain/dailyExpense';
import { AddConsumption } from './budget.actions';

@State({
    name: 'dailyExpense',
    defaults: {
        datetime: new Date(),
        consumptions: [],
    }
})
export class DailyExpenseState {
    @Action(AddConsumption)
    addConsumption(context: StateContext, action:AddConsumption){
        const state = context.getState();
        context.setState({
            ...state,
            consumptions: [
                ...state.consumptions,
                // this is the new consumption instance that we add
                action.consumption,
            ],
        });
    }
}

name은 Store에서 State를 구분하는 역할을 합니다.

따라서 유일(Unique)한 이름을 부여해야만 합니다.


기본값은 날짜와 소비내역 배열로 하였습니다.


State class에는 action과 dependency를 정의합니다.

저는 아직 dependency는 정의하지 않았구요.

action만 정의하였습니다.


Action 추가에서 action의 class를 만들었죠.

실제 수행되는 코드는 State안에 있습니다.

@Action annotation을 사용합니다.

context와 action을 인자로 받는 method를 만듭니다.

context에는 ngxs Store에 저장된 State가 담겨있습니다.

그것을 가져와서 action을 수행합니다.


3. Select 활용


이제 실제로 Component에서 State를 활용해보겠습니다.

먼저 app.module.ts에 import를 해주어야합니다.

...
import { NgxsModule } from '@ngxs/store';
import { DailyExpenseState } from './budget/budget.state';

@NgModule({
  declarations: [
    ...
  ],
  imports: [
    ...
    NgxsModule.forRoot([
      DailyExpenseState
    ])
  ],
  bootstrap: [AppComponent]
})
export class AppModule { }

ngxs 모듈에 정의한 State를 넣어주었습니다.


다음은 State를 사용할 Component의 코드를 보겠습니다.

...
import { Store, Select } from "@ngxs/store";
import { Observable } from 'rxjs';

@Component({
    ...
})
export class BudgetComponent implements OnInit {
    ...
    // ngxs select
    @Select(state => state.dailyExpense) dailyExpense$: Observable<DailyExpense>;

    // ngxs store dependency injection
    constructor(private store: Store) { }

    ngOnInit() {
        this.balance = this.budget;
        this.date = new FormControl(new Date());

        this.dailyExpense$.subscribe((dailyExpense) => {
            // using state data
            ...
        })
    }

    // using ngxs action 
    addConsumption(consumption: Consumption) {
        this.store
            .dispatch(new AddConsumption(consumption));;
    }
}

State를 조회하기 위해 @Select annotation을 사용합니다.

State중 가져올 값을 lambda 형태로 정의해주면 됩니다.

그리고 저장할 변수값을 정하죠. 

보통 $를 붙여서 state임을 표시합니다. 


타입을 보면 아시겠지만 state는 rxjs의 Observable 입니다.

따라서 subscribe하면 값이 화면에 동적으로 반영되죠.


state를 변경할 때는 설명드린바와 같이 action을 사용합니다.

action을 사용할 때에는 생성자에 주입한 Store를 이용합니다.

Store에 action 객체를 생성하여 dispatch하는 형태입니다.


복잡해보이지만 천천히 살펴보시면 쉽게 이해가 되실 겁니다.

지난 포스팅의 ngxs의 개념이 도움이 되실거에요.

(http://dschci.tistory.com/111)


아래는 ngxs를 기반으로 동작하는 화면입니다.


ngxs를 활용한 화면 예제


다음에는 동작화면의 Material Form에 대해 알아볼게요.

진행하는 작업은 github에서 보실 수 있습니다.


소스주소: https://github.com/jsrho1023/account-book

'IT Tech > Angular' 카테고리의 다른 글

Angular Forms (Validation)  (0) 2018.10.14
Angular Forms (Simple)  (0) 2018.10.07
Angular State Management (NGXS)  (0) 2018.09.15
Npm 거슬리는 pacakge-lock.json?  (2) 2018.09.02
Angular 업데이트(Update from 5 to 6)  (0) 2018.05.19

TechTrip IT Tech/Angular