NGXS의 기본 이해

51515 단어 Angularngxstech

NGXS의 기초 이해


NGXS는 Anglar의 상태 관리 라이브러리입니다.
Anglar의 상태 관리에 대해 말하자면 아마도 많은 사람들이 NgRx를 생각할 것이다
NGXS는 NgRx보다 쉽고 간편한 상태 관리를 제공합니다.
https://www.ngxs.io/

NGXS를 시작하기 전에.


NGXS를 시작하기 전에 기본적인 다음 개념을 이해하면 이해가 더 빠르겠죠.
  • 류실진기의 기초
  • Redux의 개념
  • 기본 rx.js의 예법, Observable의 사용 방법

    NGXS의 구성 요소

  • Store
  • Actions
  • State
  • Selects
  • 각 항목의 관계도는 아래 사이트에도 명확하게 기재되어 있다.
    https://www.ngxs.io/concepts/intro

    NGXS 시작


    우선 간단한 구성으로 NGXS의 코드를 사용하는 절차를 확인하자.
    이번에는 간단한 todo 목록 형식으로 다음의DI를 통해 상태 관리를 진행하는 프로젝트입니다.
    NGXS를 활용한 활용 상태 관리로의 이전을 추진한다.
    import { Injectable } from '@angular/core';
    
    @Injectable({
      providedIn: 'root'
    })
    export class TodoService {
    
      todolist = [
        {title:"牛乳を買いに行く",expire_at:"2022/01/05",priority:"high"},
        {title:"本を読み切る",expire_at:"2022/01/05",priority:"high"},
        {title:"部屋を片付ける",expire_at:"2022/01/05",priority:"normal"},
      ]
    
      constructor() { }
    
      add(form: any) {
        this.todolist.push({...form})
      }
    }
    
    이쪽 서비스의 코드를 사용한 확인은 아래의 글을 참조하십시오.
    https://zenn.dev/mikakane/articles/angular_1_tutorial
    이번 샘플 코드는 다음 URL에서도 확인할 수 있다.
    https://stackblitz.com/edit/angular-ivy-abjxkn

    환경 구조


    NGXS를 시작할 때 먼저 프로그램 라이브러리를 설치합니다.
    npm install @ngxs/store
    

    Action의 정의


    라이브러리 설치 완료
    먼저 상태 관리에 사용되는 Action의 정의부터 시작하십시오.
    Action은 상태 데이터 작업에 대한 요약 정의입니다.
    이번에는 todo 리스트와 추가 todo 리스트를 정의했습니다.
    todo.actions.ts
    export namespace TodoAction {
      export class Add {
        static readonly type = '[Todo] Add';
        constructor(public todo: any) {}
      }
    
      export class GetAll {
        static readonly type = '[Todo] GetAll';
      }
    }
    
    NGXS에서 어셈블리 작업 상태에서
    Action 정의 클래스 게시 작업 요구 사항을 사용합니다.
    dd 등 유효한 부하가 있는 작업 요청
    TodoAction.Add처럼 클래스 구조기에서 매개변수 정의하기
    작업에 필요한 데이터를 저장할 수 있습니다.

    State의 정의


    작업이 정의되면 다음 정의는 State입니다.
    State는 상태 관리 객체로서의 데이터 형식입니다.
    이 데이터와 연관된 Actions를 실행하는 것은 상태 관리의 핵심을 담당하는 요소이다.
    todo.state.ts
    import { Injectable } from '@angular/core';
    import { State, Action, StateContext } from '@ngxs/store';
    import { TodoAction } from './todo.actions';
    
    @State<any[]>({
      name: 'todos',
      defaults: [
        { title: '牛乳を買いに行く', expire_at: '2022/01/05', priority: 'high' },
        { title: '本を読み切る', expire_at: '2022/01/05', priority: 'high' },
        { title: '部屋を片付ける', expire_at: '2022/01/05', priority: 'normal' },
      ],
    })
    @Injectable()
    export class TodoState {
      constructor() {}
    
      @Action(TodoAction.GetAll)
      getAll(ctx: StateContext<any[]>) {
        const state = ctx.getState();
        return state;
      }
    
      @Action(TodoAction.Add)
      addHero(ctx: StateContext<any[]>, action: TodoAction.Add) {
        const state = ctx.getState();
        state.push(action.todo);
        ctx.setState(state);
      }
    }
    
    클래스 장식물의 @State는 State를 정의하는 장식물입니다.
    defaults에서state의 초기 데이터를 정의할 수 있습니다.
    @State<any[]>({
      name: 'todos',
      defaults: [
        { title: '牛乳を買いに行く', expire_at: '2022/01/05', priority: 'high' },
        { title: '本を読み切る', expire_at: '2022/01/05', priority: 'high' },
        { title: '部屋を片付ける', expire_at: '2022/01/05', priority: 'normal' },
      ],
    })
    @Injectable()
    export class TodoState {
        // ...
    }
    
    State 클래스 내부에서 중음을 사용하여 State 작업을 정의합니다.
    getall은 모든 state 데이터를 가져오는 동작을 정의합니다.
    모든 작업은 @Action 장식기를 사용하여 Action과 연결된 형식으로 이루어집니다.ctx.getState는 State 데이터를 직접 가져올 수 있는 함수입니다.
    export class TodoState {
      @Action(TodoAction.GetAll)
      getAll(ctx: StateContext<any[]>) {
        const state = ctx.getState();
        return state;
      }
      // ...
    }
    
    add에서 추가 작업을 정의했습니다.
    getState를 통해 현재state를 가져오고push로 조작한 후
    ctx.setState에서 새 State로 업데이트되었습니다.
    export class TodoState {
      // ...
      @Action(TodoAction.Add)
      add(ctx: StateContext<any[]>, action: TodoAction.Add) {
        const state = ctx.getState();
        state.push(action.todo);
        ctx.setState(state);
      }
    }
    

    구성 요소 활용


    구성 요소 인용은 매우 간단합니다.
    NGXS에서 데이터 참조@Select를 사용하여 속성을 정의한 후 수행됩니다.
    이번 State 정의는 비동기 처리를 처리하지 않았습니다.@Select의 귀속에 따라 은연중에 Observable로 변환됩니다.
    import { Select } from '@ngxs/store';
    import { Observable } from 'rxjs';
    import { TodoState } from '../todo.state';
    
    @Component({ 
      //...
    })
    export class TopPageComponent implements OnInit {
      @Select(TodoState) todolist$: Observable<any[]>;
      constructor() {}
      ngOnInit() {}
    }
    
    템플릿에서 이 생성된 todolist$을 사용할 때
    async관을 사용하면 다음과 같이 설치할 수 있습니다.
    <div class="divide-y">
      <div class="p-2" *ngFor="let todo of todolist$ | async">
        {{ todo.title }}
      </div>
    </div>
    
    State의 데이터 조작은 DI로 Store를 주입하고 디스패치 함수를 호출하여 진행된다.
    자체 new Action 클래스를 통해 dispatch 함수에 전달되는 매개변수
    해당 작업과 연관된 State 처리를 자동으로 수행합니다.
    import { Component, OnInit } from '@angular/core';
    import { Router } from '@angular/router';
    import { Store } from '@ngxs/store';
    import { TodoAction } from '../todo.actions';
    
    @Component({
        // ...
    })
    export class FormPageComponent implements OnInit {
      constructor(private store: Store, private router: Router) {}
    
      add() {
        this.store.dispatch(
            new TodoAction.Add({
                title: '引っ越しの見積もりを取る',
                expire_at: '2022-01-01',
                priority: 'high',
            })
        );
        this.router.navigateByUrl('/');
      }
    }
    
    누군가가 이곳을 눈치챘을지도 모르지만, Action의 getall은 설치할 필요가 없습니다.
    state 자체의 취득은 @Select로 간단하게 할 수 있습니다.
    검색과 아이디 취득 등에 따라 get계 동작이 필요한 경우가 많죠.

    비동기식 Action 활용


    여기 는 간단하게 동기화 된 기술 을 진행하였다
    많은 Action 처리는 비동기적으로 이루어져야 한다.
    비동기 동작을 수행할 때, Action 내부는 다음과 같이 Observable로 되돌아옵니다.
    import { timer } from 'rxjs';
    import { tap } from 'rxjs/operators';
    import { TodoAction } from './todo.actions';
    
    // ... some decorator
    export class TodoState {
      // ...
      @Action(TodoAction.Add)
      addHero(ctx: StateContext<any[]>, action: TodoAction.Add) {
        return timer(2000).pipe(
          tap((r) => {
            const state = ctx.getState();
            state.push(action.todo);
            ctx.setState(state);
          })
        );
      }
    }
    
    여기서 비동기 처리에 영향을 주고 싶을 때subscribe가 아닌 pipe tap을 사용하십시오.
    subscribe에서 정의된 역할은subscribe 내 처리가 완료되기 전에 디스패치의 토대에서push가 이벤트를
    원하는 동작을 얻을 수 없습니다.
    구성 요소 관련 이벤트에 불이 났을 때
    디스패치의 반환값이 observable이기 때문에
    subscribe를 통해 동작이 완성되기를 기다릴 수 있습니다.
    import { Component, OnInit } from '@angular/core';
    import { TodoAction } from '../todo.actions';
    
    @Component({
        // ...
    })
    export class FormPageComponent implements OnInit {
        // ...
        add() {
            this.store
                .dispatch(
                    new TodoAction.Add({
                        title: '引っ越しの見積もりを取る',
                        expire_at: '2022-01-01',
                        priority: 'high',
                    })
                )
                .subscribe((r) => {
                    this.router.navigateByUrl('/');
                });
        }
    }
    
    dispatch 자체의 반환값은observable
    값으로 변경된 State를 얻을 수 있습니다.

    Select의 그림 전시회


    NGXS에서 @Select는 상태를 구성 요소와 연결하는 데 필요한 기록입니다.
    https://www.ngxs.io/concepts/select

    기본 @Select 기법


    Select의 기본 기재법에서 State 레벨을 Select 장식물에 건네주기
    구성 요소를 통해 State의 모든 데이터를 수신할 수 있습니다.
    다음 예에서 animals Observable은 동물 이름 일람표를 받아들이는 배열을 실시했다.
    import { Select } from '@ngxs/store';
    import { ZooState } from './zoo.state';
    
    @Component({ ... })
    export class ZooComponent {
      // Reads the name of the state from the state class
      @Select(ZooState) animals$: Observable<string[]>;
    }
    

    복잡한 셀렉트 장식물


    또한 함수를 Select 장식기에 전달하여 state 필터를 실현할 수 있습니다.
    필터 함수에서 매개 변수를 통해 전체 프로그램의state를 얻을 수 있습니다.
    다음 예에서 animals Observable에서 zoo State 클래스의state에서 animals 키만 꺼냅니다.
    여기서 조오는 State 클래스 선언 시 구현되는 State의name 요소입니다.
    import { Select } from '@ngxs/store';
    import { ZooState } from './zoo.state';
    
    @Component({ ... })
    export class ZooComponent {
      // Also accepts a function like our select method
      @Select(state => state.zoo.animals) animals$: Observable<string[]>;
    }
    
    상기 Select 처리는 구성 요소에 편리하지만 다른 한편, 볼록대의 정의는 복잡해지기 쉽다.
    시간이 있으면 State의 필기 기능을 고려해 보십시오.

    Select 프로세스의 메모화


    위의 State 필터링
    State Class가 static 에 선언되면 쉽게 호출할 수 있습니다.
    NGXS라고 불리는 Memoized Selectors의 기능입니다.
    Memoized Selectors는 State 내에서 Selector decorder를 사용하여 static 함수로 구현됩니다.
    import { Injectable } from '@angular/core';
    import { State, Selector } from '@ngxs/store';
    
    @State<string[]>({
      name: 'animals',
      defaults: []
    })
    @Injectable()
    export class ZooState {
      @Selector()
      static pandas(state: string[]) {
        return state.filter(s => s.indexOf('panda') > -1);
      }
    }
    
    Memoized Selectors 사용 시
    Memoized Selectors의 함수를 구성 요소의 Select decoller에 전달합니다.
    import { Select } from '@ngxs/store';
    import { ZooState, ZooStateModel } from './zoo.state';
    
    @Component({ ... })
    export class ZooComponent {
      // Uses the pandas memoized selector to only return pandas
      @Select(ZooState.pandas) pandas$: Observable<string[]>;
    }
    

    프로그램state 작업


    셀렉터 장식물을 사용하지 않아도
    select 함수를 통해 store 대상에서 값을 얻을 수 있는 DI Store도 있습니다.
    select 함수로서의 매개 변수 함수에서 첫 번째 매개 변수를 통해 전체 응용의state를 얻을 수 있습니다
    각 State 클래스의name 요소를 사용하여 각 State 클래스의 상태에 액세스할 수 있습니다.
    import { Store } from '@ngxs/store';
    
    @Component({ ... })
    export class ZooComponent {
      animals$: Observable<string[]>;
    
      constructor(private store: Store) {
        this.animals$ = this.store.select(state => state.zoo.animals);
      }
    }
    

    State용 SnapShot 확보


    Store 클래스 DI를 통한 State 작업 시
    select 함수 외에도 selectSnapShot 함수를 사용할 수 있습니다.
    selectSnapshot 함수에서 Observable이 아니라 간단한 값으로
    실행 시 State 값을 적용할 수 있습니다.
    @Injectable()
    export class JWTInterceptor implements HttpInterceptor {
      constructor(private store: Store) {}
    
      intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
        const token = this.store.selectSnapshot<string>((state: AppState) => state.auth.token);
        req = req.clone({
          setHeaders: {
            Authorization: `Bearer ${token}`
          }
        });
    
        return next.handle(req);
      }
    }
    

    좋은 웹페이지 즐겨찾기