내용으로 건너뛰기
Angular 상태 관리: 프로젝트를 발전시키는 모범 사례

Angular 상태 관리: 프로젝트를 발전시키는 모범 사례

효과적인 Angular 상태 관리를 위한 최상의 전략과 관행은 무엇입니까? 여기를 읽고 앱 성능을 향상시키는 방법을 알아보세요.

14min read

데이터 통신이 많은 Angular 앱을 구축할 때 데이터 효율성, 네트워크 대기 시간, 확장성, 리소스 관리, 테스트 및 UX와 같은 요소를 해결하는 전체적인 접근 방식을 고려해야 합니다. 또한 앱의 확장 가능하고 일관성 있는 상태를 유지하면서 데이터 충돌을 방지하는 데 매우 중요한 것 중 하나는 효과적인 Angular 상태 관리입니다. 그렇지 않으면 데이터는 어디에나 존재하게 될 것입니다.

그러나 Angular에서 상태 관리란 무엇이며 정확히 어떻게 처리해야 합니까? 다음을 사용하여 Angular State Management 모범 사례를 살펴보겠습니다. Ignite UI for Angular 그리고 다음과 같이 접근하는 방법을 살펴보십시오. Service Basic 구현 활용알엑스제이및 상태 관리는NgRx, r에서 지원 EAL 코드 예제.

Try Ignite UI Angular For Free

Angular의 상태 관리란?

이는 Angular 애플리케이션의 상태를 처리하고 유지 관리하기 위한 다양한 기술과 전략을 포함하는 프로세스입니다.이 경우 웹 애플리케이션의 상태는 외부 서비스에서 가져오고 앱에서 조작 및 표시하는 데이터를 포함하여 애플리케이션에서 사용하는 모든 데이터와 애플리케이션이 지정된 사용자에 대한 올바른 UI를 빌드하기 위해 생성, 저장 및 사용하는 모든 데이터를 나타냅니다.

간단히 말해서 Angular에서 상태 관리가 필요한 이유가 궁금할 수 있습니다. 새로운 페이지나 새로운 기능, 현재 상태(예: 사용자가 로그인했는지 여부)를 나타내는 앱의 모든 새로운 UI는 앱의 복잡성을 가중시킵니다. 일단 단순한 앱의 범위를 벗어나면 체계적인 상태 관리 방법을 적용하지 않으면 이 모든 것을 관리하기가 어렵습니다. Angular에서 이 작업을 수행하는 가장 일반적인 방법은 데이터를 검색, 공유 및 업데이트할 뿐만 아니라 깔끔하고 잘 구성된 방식으로 데이터에 액세스, 상호 작용 및 추가 수정할 수 있도록 하는 상태 컨테이너입니다.

전화를 걸거나 필요한 때를 아는 것

응용 프로그램이 확장되고 복잡해짐에 따라 일반적으로 많은 데이터를 처리해야 하며 대규모 프로젝트에서 데이터를 관리하는 것이 까다로울 수 있습니다. 여기에서 비동기 데이터로 작업하고, 추적해야 할 데이터 변경 사항이 더 많고, 더 많은 코드로 작업할 때 상황이 훨씬 더 복잡해집니다. 지속적인 변경 컴퓨팅, 리플로우 또는 API 요청과 같이 배후에서 너무 많은 일이 진행되어 브라우저의 기본 스레드를 차단하고 앱이 응답하지 않게 될 수도 있습니다. 상태 관리를 통해 체계적으로 접근하지 않으면 위의 내용은 버그, 기술적 부채 등을 수정하는 데 너무 많은 비용을 의미할 것입니다.

그렇다면 State Management Angular 언제 사용합니까? 다음은 몇 가지 사용 사례입니다.

  • 애플리케이션 복잡성 증가

최소한의 데이터 흐름을 가진 간단한 앱에는 상태 관리가 필요하지 않을 수 있지만 여러 구성 요소, 많은 데이터 상호 작용, 증가하는 기능 집합 및 복잡한 사용자 인터페이스가 있는 대규모 소프트웨어 프로젝트에서 특히 유용합니다.

이를 통해 얻을 수 있는 것은 질서 유지, 데이터 일관성 유지, 성능 향상, 향상된 UX + 반응형 인터페이스 제공입니다.

  • Sharing data 

상태 관리는 구성 요소 또는 서비스와 같은 애플리케이션의 서로 다른 부분 간에 데이터를 공유해야 하는 경우에 필수적입니다.

이를 통해 얻을 수 있는 것은 중앙 집중식 데이터 관리 및 간소화된 데이터 공유입니다.

  • 비동기 작업에서

앱에 API에서 데이터 가져오기, 실시간 업데이트 처리 또는 사용자 상호작용 처리와 같은 비동기 작업이 포함된 경우

여기서 얻을 수 있는 것은 간소화된 비동기 데이터 흐름과 반응형 UIS입니다.

  • 예측 가능한 상태 변화를 목표로 하는 경우

Angular 응용 프로그램에서 상태가 변경되는 방법과 시기를 엄격하게 제어하고 싶으십니까? 프로세스를 용이하게 할 수 있는 다양한 상태 관리 라이브러리가 있습니다.

여기서 달성 가능한 것은 예측 가능하고 디버그하기 쉬운 코드베이스를 보장하는 것입니다.

개발자의 작업을 더 쉽게 만들기: Ignite UI를 사용한 상태 관리 모범 사례 Angular

에 관해서 Angular에서 상태를 관리하는 방법 , 앱의 복잡성, 프로젝트 요구 사항, 지식 및 선호도에 따라 다양한 기술과 도구가 있습니다. 예를 들어, 상태가 단일 구성 요소와 관련된 경우 구성 요소 자체 내에서 Angular 상태를 관리할 수 있습니다. 여기에서 데이터를 저장하고 업데이트하려면 클래스 속성과 변수에 의존해야 합니다. 대규모 애플리케이션의 경우 상태 관리 라이브러리를 사용하는 것이 좋습니다.

그러나 이것을 자세히 살펴보고 최고의 Angular 상태 관리 기술을 살펴보겠습니다.

  • Rxjs를 상태를 관리하는 좋은 방법으로 활용하는 서비스 기본 구현

서비스 및 RxJS를 사용하는 Angular의 상태 관리는 강력하고 유연한 접근 방식이며 다음은 몇 가지 모범 사례입니다.

  • Single responsibility principle 

각 서비스에 단일 책임이 있는지 확인합니다. 특정 작업(예: 사용자 로깅 및 인증, 사용자 데이터 관리 등)을 처리하도록 서비스를 설계하면 코드베이스를 깔끔하고 유지 관리 가능한 상태로 유지할 수 있습니다. 각 서비스는 상태의 특정 부분을 관리하여 디버그 및 테스트를 더 쉽게 해야 합니다.

  • 단일 정보 소스로서의 서비스

서비스를 주에 대한 단일 정보 소스로 취급합니다. 구성 요소는 상태 정보 및 업데이트를 위해 서비스에 의존해야 하며, 이를 통해 단방향 데이터 흐름을 촉진하고 응용 프로그램을 더 쉽게 추론할 수 있어야 합니다.

  • 서비스에서 상태 논리를 캡슐화합니다

상태 논리를 구성 요소가 아닌 서비스 내부에 유지합니다. 서비스는 비즈니스 로직 및 상태 관리를 처리해야 하며, 컴포넌트는 프리젠테이션과 상호 작용에 초점을 맞춥니다. 이러한 문제 분리는 테스트 가능성과 재사용성을 향상시킵니다.

  • Error handling 

서비스 내에서 오류 처리를 구현합니다. 관찰 가능 항목에서 오류를 포착하고 처리하여 원활한 사용자 경험을 제공하고 애플리케이션 충돌을 방지합니다.

  • 상태 관리를 위한 RxJs 연산자 및 주체 활용

이를 위해서는 먼저 올바른 주제(기본 멀티캐스트 객체)를 선택하여 어떤 상태도 유지하지 않고 여러 가입자에게 값을 내보냅니다. 이벤트나 액션에 적합합니다. 다음으로 동작 주체를 정의합니다. 초기 값이 필요하고 현재 값을 새로운 구독자에게 내보내는 Subject 유형입니다. 이는 상태를 초기화하고 새 구독자에게 항상 최신 상태를 제공할 수 있으므로 상태 관리에 유용합니다. ReplaySubject: 지정된 수의 이전 값을 새 구독자에게 내보냅니다. 이전 상태 값을 재생해야 하는 경우에 유용합니다. 다음으로, AsyncSubject를 사용하면 완료 시 마지막 값(마지막 값만)을 내보낼 수 있습니다. 최종 내보낸 값만 필요한 시나리오에 유용합니다.

2단계로 여러 상태 스트림을 사용할 수 있습니다. combineLatest, withLatestFrom 등과 같은 RxJS 연산자를 사용하여 여러 상태 스트림을 결합합니다. 여러 관찰 가능 항목을 기반으로 상태를 파생해야 하는 경우가 많습니다. combineLatest와 같은 연산자를 사용하면 다른 상태 스트림의 조합을 기반으로 새로운 상태 관찰 가능 항목을 만들 수 있습니다. 그런 다음, 서비스 및 해당 상태 관리 논리에 대한 단위 테스트를 작성합니다. 테스트를 통해 서비스가 예상대로 작동하는지 확인하는 것은 애플리케이션 안정성을 유지하고 문제를 조기에 파악하는 데 매우 중요합니다.

서비스를 사용하면 날씨 데이터를 가져오고 저장하기 위한 논리를 중앙 집중화할 수 있습니다. 이렇게 하면 날씨 데이터가 필요한 모든 구성 요소가 단일 정보 소스에서 데이터를 얻을 수 있습니다.

기상청

interface WeatherData {
    temperature: number;
   description: string;
}
@Injectable({
  providedIn: 'root'
})
export class WeatherService {
  private apiKey = 'YOUR_API_KEY';
  private _weather: BehaviorSubject<WeatherData | null> = new BehaviorSubject<WeatherData | null>(null);
  public weather$: Observable<WeatherData | null> = this._weather.asObservable();
constructor(private http: HttpClient) { }
  private getApiUrl(location: string): string {
   return `https://api.weatherapi.com/v1/current.json?key=${this.apiKey}&q=${location}`;
  }
  fetchWeather(location: string): Observable<WeatherData | null> {
    const apiUrl = this.getApiUrl(location);
    return this.http.get<WeatherData>(apiUrl).pipe(
      tap((data: WeatherData) => this._weather.next(data)),
      catchError(error => {
        console.error('Error fetching weather data', error);
        this._weather.next(null);
        return of(null);
      })
    );
  }
}

'WeatherService'는 API에서 데이터를 가져와 'BehaviorSubject'에 저장하여 서비스를 주입하는 모든 구성 요소에서 액세스할 수 있도록 합니다. rxjs'BehaviorSubject'를 사용합니다. 응용 프로그램이 데이터 변경 내용을 사후 대응적으로 관리할 수 있도록 합니다. 서비스에서 날씨 데이터가 업데이트되면 'BehaviorSubject'에 가입된 모든 구성 요소가 자동으로 알림을 받고 그에 따라 뷰를 업데이트할 수 있습니다.

Component TS file: 

export class WeatherDisplayComponent implements OnInit {
    weather$: Observable<WeatherData | null>;

    constructor(private weatherService: WeatherService) {
        this.weather$ =this.weatherService.weather$;
    }

    ngOnInit(): void {
        this.weatherService.fetchWeather('New York');
    }
}

구성 요소 HTML 파일:

<div *ngIf="weather$ | async as weather"> 
   <h2>Current Weather</h2> 
   <p>Temperature: {{ weather.temperature }}°C</p> 
   <p>Description: {{ weather.description }}</p> 
</div> 

구성 요소는 데이터 가져오기 또는 상태 관리에 대한 걱정 없이 데이터를 표시하고 사용자 상호 작용을 처리하는 데 계속 중점을 둡니다. 이러한 문제 분리를 통해 구성 요소를 더 쉽게 작성, 테스트 및 유지 관리할 수 있습니다.

다음은 NgRx를 사용한 상태 관리의 예입니다.

Angular 애플리케이션에서 상태 관리를 위해 NgRx를 사용하면 특히 더 크고 복잡한 애플리케이션의 경우 추가적인 이점을 제공할 수 있습니다. NgRx는 Redux 패턴을 사용하여 Angular 애플리케이션에서 반응 상태를 관리하기 위한 라이브러리입니다.

날씨 데이터의 구조를 정의합니다.

weather.model.ts 

export interface WeatherData {
       temperature: number;
       description: string;
    }
export interface WeatherState {
       weather: WeatherData | null; 
       loading: boolean; 
       error: string | null; 
    }

날씨 기능에서 다른 이벤트를 나타내기 위해 Actions 를 정의합니다.

weather.actions.ts 

export const loadWeather = createAction(
      '[Weather] Load Weather',
      props<{ location: string }>()
    );
    export const loadWeatherSuccess = createAction(
     '[Weather] Load Weather Success',
      props<{ weather: WeatherData }>()
    );
    export const loadWeatherFailure = createAction(
      '[Weather] Load Weather Failure', 
      props<{ error: string }>()
    );  

액션을 기반으로 상태 변경을 처리하는 리듀서를 정의합니다.

weather.reducer.ts

export const initialState: WeatherState = {
      weather: null,
      loading: false,
      error: null,
    };
    export const weatherReducer = createReducer(
      initialState,
      on(loadWeather, (state) => ({
       ...state,
       loading: true,
       error: null,
      })),
      on(loadWeatherSuccess, (state, { weather }) => ({
       ...state,
       weather,
       loading: false,
      })),
     on(loadWeatherFailure, (state, { error }) => ({
       ...state,
       loading: false,
       error,
      }))
    );

API 호출과 같은 부작용을 처리하기 위해 부작용을 처리합니다.

weather.effects.ts 

@Injectable()
export class WeatherEffects {
  loadWeather$ = createEffect(() =>
    this.actions$.pipe(
      ofType(loadWeather),
      mergeMap(action => this.http.get<WeatherData>(`https://api.weatherapi.com/v1/current.json?key=YOUR_API_KEY&q=${action.location}`).pipe(
        map(weather => loadWeatherSuccess({ weather })),
        catchError(error => of(loadWeatherFailure({ error: error.message })))
      )
      ))
  );
  constructor(private actions$: Actions, private http: HttpClient) { }
}

app.module.ts에서 NgRx 저장소와 효과를 등록하여 애플리케이션 전체에서 사용할 수 있도록 합니다.

@NgModule({
       imports: [
        BrowserModule,
        HttpClientModule,
        StoreModule.forRoot({ weather: weatherReducer }),
        EffectsModule.forRoot([WeatherEffects]),
       ]
    }) 

날씨 피처 상태에서 상태 조각을 파생하기 위해 날씨 상태에 대한 선택기를 정의합니다.

weather.selectors.ts 

export const selectWeatherState = createFeatureSelector<WeatherState>('weather');
export const selectWeather = createSelector(
  selectWeatherState,
  (state: WeatherState) => state.weather
);
export const selectLoading = createSelector(
  selectWeatherState,
  (state: WeatherState) => state.loading
);
export const selectError = createSelector(
  selectWeatherState,
  (state: WeatherState) => state.error
);

저장소를 구성 요소에 주입하고 작업을 전달하여 날씨 데이터를 로드하고 표시할 상태를 선택합니다.

weather-display.component.ts 

export class WeatherDisplayComponent implements OnInit {
      weather$: Observable<WeatherData | null>;
      loading$: Observable<boolean>;
      error$: Observable<string | null>;
      constructor(private store: Store<{ weather: WeatherState }>) { 
       this.weather$ = this.store.pipe(select(selectWeather)); 
       this.loading$ = this.store.pipe(select(selectLoading)); 
       this.error$ = this.store.pipe(select(selectError)); 
      }
      ngOnInit(): void { 
       this.store.dispatch(loadWeather({ location: 'New York' })); 
      }
    }

구성 요소 HTML 파일:

<div *ngIf="loading$ | async">Loading...</div>
<div *ngIf="error$ | async as error">{{ error }}</div>
<div *ngIf="weather$ | async as weather">
   <h2>Current Weather</h2>
   <p>Temperature: {{ weather.temperature }}°C</p>
   <p>Description: {{ weather.description }}</p>
</div>

2. 상태 관리 라이브러리 사용 고려 – NgRx 

NgRx는 반응형 프로그래밍 원리를 사용하여 Angular 애플리케이션의 상태를 관리하기 위한 강력한 라이브러리입니다. Redux 패턴에서 영감을 얻었으며 Angular와 잘 통합되어 응용 프로그램의 상태를 쉽게 유지 관리하고 디버그할 수 있습니다.

NgRx를 사용한 Angular 상태 관리

더 명확하게하기 위해 설명 된 핵심 개념은 다음과 같습니다.

Store– 일관된 상태 관리를 보장하고, 단방향 데이터 흐름을 촉진하며, 애플리케이션 상태를 처리하는 구조화된 방법을 제공합니다. 전체 응용 프로그램 상태를 변경할 수 없는 개체 트리로 나타냅니다. 이 트리의 각 노드는 observables를 통해 액세스되는 애플리케이션 상태의 특정 부분에 해당하므로 구성 요소가 상태의 특정 조각을 구독할 수 있습니다.

작업– NgRx 기반 애플리케이션의 이벤트를 설명합니다. 이는 응용 프로그램 내에서 발생한 일을 나타내며 사실에 대한 진술로 간주될 수 있습니다.

Reducers– 현재 상태와 액션을 취하고 새로운 상태를 반환하는 함수입니다. 리듀서는 액션에 대한 반응으로 상태가 어떻게 변하는지를 지정한다.

Selectors– 저장소에서 상태 조각을 선택하는 데 사용되는 함수입니다. 상태 구조를 캡슐화하는 데 도움이 되며 더 복잡한 선택기를 생성하도록 구성할 수 있습니다.

효과– 부작용은 매장 밖에서 처리됩니다. 효과는 특정 작업을 수신하고 API 호출과 같은 작업을 수행하고 결과에 따라 새 작업을 전달하는 클래스입니다. 그들은 Angular Dependency Injection을 사용하고 RxJS 관찰 가능 항목을 활용하여 부작용을 관리합니다.

NgRx를 사용할 때의 빠른 팁과 요령

먼저 상태를 구성하고 기능 상태 분리를 수행합니다. 이렇게 하려면 상태를 기능 모듈별로 구분합니다. 각 기능 모듈에는 모듈화되고 유지 관리 가능한 상태를 유지하기 위해 고유한 상태 조각이 있어야 합니다. 각 기능 모듈 내에서 일관된 폴더 구조(예: actions, reducers, selectors 및 effects)를 사용합니다.

그런 다음 명확한 작업 유형을 정의할 수 있습니다.Action Naming의 경우 설명 작업 유형입니다. 액션 타입에 액션 타입이 속한 피처를 접두사로 붙입니다(예: '[Weather] Load Weather'). Action Payloads의 경우 강력한 형식의 페이로드를 사용합니다. 또한 형식 안전성을 보장하기 위해 페이로드에 대한 인터페이스를 정의해야 합니다. NgRx 측면에서 또 다른 중요한 것은 순수한 리듀서를 작성하는 것입니다. 항상 리듀서가 순수 함수인지 확인하고 기존 상태를 변경하는 대신 항상 새 상태 객체를 반환합니다. 그리고 리듀서의 로직을 최소한으로 유지하십시오. 리듀서에서 부작용이나 복잡한 logic 를 피하십시오. 효과에 그것들을 위임하십시오.

상태 액세스를 위해 선택기를 사용하는 것도 고려해야 할 사항입니다. 선택기를 사용하여 상태 구조를 캡슐화할 수 있습니다. 이렇게 하면 구성 요소 코드를 깔끔하게 유지하고 상태 모양을 추상화하는 데 도움이 됩니다. 또는 선택기를 구성하여 더 복잡한 상태 선택을 만들 수 있습니다. 해야 할 중요한 일은 효과를 사용하여 API 호출, 로깅 등과 같은 부작용을 처리하는 것입니다. 이렇게 하면 리듀서가 순수하고 구성 요소가 깨끗하게 유지됩니다. 그리고 항상 효과의 오류를 처리해야 한다는 점을 명심하십시오. 적절한 작업을 사용하여 오류 상태를 관리합니다.

마지막으로 테스트 측면에서 주의해야 할 몇 가지 사항이 있습니다. 리듀서에 대한 단위 테스트를 작성하여 주어진 작업에 대해 올바른 상태를 반환하는지 확인합니다. 효과를 테스트하여 올바른 작업을 전달하고 부작용을 적절하게 처리하는지 확인합니다.'MockStore'를 사용하여 실제 NgRx 저장소와 격리된 구성 요소를 테스트하는 것이 좋습니다.

Angular State Management 예제를 통해 이를 보다 생생하게 보여 보겠습니다.

날씨 앱을 만들고 있다고 상상해 보세요. 여기에서 API에서 날씨 업데이트에 대한 데이터를 가져와 애플리케이션의 여러 부분에 표시해야 합니다. 이를 위해 API 요청을 처리하고 지정된 데이터를 저장하는 Angular에서 WeatherService를 만들 수 있습니다. 이 서비스는 날씨 정보에 액세스하고 표시하기 위해 다양한 구성 요소에 주입될 수 있습니다.

싸다

결론적으로, RxJS 및 NgRx와 함께 서비스를 사용하는 Angular 애플리케이션에 대한 이러한 상태 관리 기술은 프로젝트 요구 사항 및 팀 전문 지식에 따라 신중하게 고려해야 하는 고유한 이점과 절충안을 제공합니다. 결국 결정은 프로젝트의 특정 요구 사항, 개발 제약 조건 및 팀 기능의 우선 순위를 지정해야 합니다. 개발자는 이러한 요소를 신중하게 평가하여 목표에 가장 잘 부합하고 Angular 응용 프로그램을 성공적으로 제공할 수 있는 상태 관리 방법을 선택할 수 있습니다.

Ignite UI for Angular library

데모 요청