# 개요
Akita 라이브러리란 Javascript Application을 위한 State 관리 라이브러리이다.
Rxjs 위에 만들어진 state 관리 패턴이라고 할 수 있다.
여러개의 Data Store를 만들고, 실시간으로 Data 갱신을 받기 위한 용도이다. Data Store Model은 Observable 형식으로 제공된다.
Akita는 함수적프로그래밍 대신에 객체 중심 디자인으로 진행된다.
프로젝트는 아래와 같은 구조로 Data의 State를 저장하고, 동작하게 된다.
# 상태관리란?
# 구성요소
- 이전
1. .service.ts <> Backend API(DB CRUD)
2. component.ts > service.ts
- component.ts 는 CRUD와 관련된 Action Event 발생시, Service 내 함수 호출
component.ts < service.ts:
- service.ts 는 CRUD를 마치고 변경된 Data 관련된 Query를 업데이트해서, component.ts가 구독하고 있는 데이터를 실시간 state로 변화시켜주어 component.ts 상에서 변화된 부분을 Rendering하게 해준다.
- 이후
1. .service.ts <> Backend API(DB CRUD) // 기존과 동일
2. component.ts > service.ts: CRUD와 관련된 Action Event 발생시, Service 내 함수 호출 //기존과 동일
component.ts < query.ts < store.ts < service.ts
// service.ts 는 CRUD를 마치고 변경사항이 발생했을 경우, store.ts 에 미리 저장되어 있던 Data를 업데이트한다.
// store.ts 는 변경된 Data를 실시간으로 query.ts로 제공한다. (store.ts에는 항상 실시간의 data가 존재한다고 생각)
3. query <> another query
// query.ts 는 store.ts의 실시간 data와 이미 존재하는 다른 query.ts와 손쉽게 상호작용하여, 원하는 query를 수행해낸다.
// sesseion.query, auth.query와 같이 공용 query에 쉽게 접근 가능?
4. component.ts < query.ts :
// component.ts 상에서는 query.ts를 통해 작업을 수행하였으면, 별도의 조치가 필요 없다.
# store.ts
- Store 정의 : Store 상태를 저장하는 single Object이다.
import { Store, StoreConfig } from '@datorama/akita';
export interface SessionState { //Session이라는 Data 객체의 State까지 존재
token: string; //Session이라는 Data 객체가 저장하는 속성
name: string; //Session이라는 Data 객체가 저장하는 속성
}
export function createInitialState(): SessionState {
return {
token: '',
name: '' //초기 State 초기화
};
}
@StoreConfig({ name: 'session' })
export class SessionStore extends Store<SessionState> {
constructor() {
super(createInitialState());
}
}
- service.ts > store.ts : service.ts가 CRUD를 마치고 변경사항이 발생했을 경우, store.ts 에 미리 저장되어 있던 Data를 업데이트할 경우
import { SessionStore } from './session.store';
export class SessionService {
constructor(private sessionStore: SessionStore, private http: HttpClient) {} //service.ts 무조건 store.ts와 dependency
updateUserName(newName: string) {
this.sessionStore.update({ name: newName }); //store.ts 상태 실시간 업데이트
}
//아래와 같은 방식으로, 변경되기 이전에 현재 state를 얻어올 수 있다.
updateUserName(newName: string) {
this.sessionStore.update(state => ({
name: newName
}));
}
//store.ts 상의 loading을 표시해줄 수 있다.
async updateUserName(newName: string) {
this.sessionStore.setLoading(true);
await this.http(...).toPromise(); //실질 CRUD 작업 수행
this.sessionStore.update({ name: newName});
this.sessionStore.setLoading(false);
}
//store.ts 상에 error를 알릴 수 있다.
async updateUserName(newName: string) {
try {
await this.http(...).toPromise();
} catch(error) {
this.sessionStore.setError(error);
}
}
//store.ts 파괴
sessionStore.destroy();
}
# query.ts
- 언뜻보면 database query라고 생각할 수 있으나, 개별 store.ts에 대한 db query는 service.ts 상에서 수행한다.
- query.ts는 db에서 1차적으로 정의된 store data를 다른 store data와 다른 query.ts 들을 참고하여, 최종적인 기능을 제공하는 역할을 하는 class이다.
import { Query } from '@datorama/akita';
import { SessionState } from './session.store';
export class SessionQuery extends Query<SessionState> { //query.ts 무조건 해당 query와 관련된 store.ts 내의 state를 상속한다.
constructor(protected store: SessionStore) { //query.ts 무조건 store.ts와 dependency
super(store);
}
// select 예제 : store로부터 하나의 slice를 선택한다.
allState$ = this.select(); //Query<SessionState>를 상속하므로, 가능하다.
isLoggedIn$ = this.select(state => !!state.token); //state.(속성값)으로 접근하고 로직까지 넣고 싶을 때, 비즈니스 기능이 정의된다.
selectName$ = this.select('name'); //단순 하나의 속성만 가져오고 싶을 때, '(속성값)"으로 넣어줌
// return은 단순 속성값
// Returns { name, age }
multiProps$ = this.select(['name', 'age']); //여러개의 속성만 가져오고 싶을 때, ['(속성값1)', '(속성값2)'] 리스트로 넣어줌
// return은 {'A':'B'... } 객체
// Returns [name, age]
multiPropsCallback$ = this.select( //여러개의 속성만 가져오고 싶되, 특정 속성값은 로직을 적용하고 싶을 때
// return은 [결과값1, 결과값2]
[state => state.name, state => state.age]
)
// getValue() 예제 : store의 raw value에 접근가능하다.
}
// component.ts 상에서 쿼리 사용하기
@Component({})
export class LoginComponent {
isLoading$ = this.sessionQuery.selectLoading(); //현재 query와 관련된 store가 loading 중인가?
error$ = this.sessionQuery.selectError(); //현재 query와 관련되 store가 error 상태인가?
constructor(private sessionQuery: SessionQuery) {} //component.ts 무조건 query.ts와 dependency
}
// The select() method returns an observable that calls distinctUntilChanged() internally, meaning it will only fire when the state changes, i.e., when there is a new reference
// query.ts 내 select() 함수로 이루어진 값들은 기본적으로, observable 객체 형식으로 전달되기 때문에, store.ts 내 state가 변경될 때만 호출된다.(초기에는 초기값을 반환한다.)
# Best Practice
https://datorama.github.io/akita/docs/best-practices
# 출처
https://datorama.github.io/akita
'[DEV] App Dev ∕ Web Front > Framework ∕ Angular' 카테고리의 다른 글
[예제로 배우는 Angular] 재사용가능한 Component - avatar image (0) | 2020.09.01 |
---|---|
[라이브러리]Gridjs : Typescript 기반 게시판 모듈 (0) | 2020.08.24 |
Angular 핵심 요약(미완) (0) | 2020.08.19 |
[라이브러리]cdk/drag-and-drop : 드래그&드롭 기능 (0) | 2020.08.19 |
[라이브러리]ng-zorro : Augular를 위한 UI Framework(Ant 디자인 철학) (0) | 2020.08.19 |
최근댓글