본문 바로가기
프로그래밍/Angular

[RxJS / angular] 19. Subject 액션 스트림으로 데이터 필터링 하기

by 신나요 2022. 8. 2.

이번 포스트에서는 액션 스트림을 사용해서 유저 인터렉션을 어떻게 처리하는지 살펴보게 됩니다. 액션 스트림과 데이터 스트림을 결합해서 데이터를 필터링하고 화면에 표시하겠습니다. select를 선택할 때 데이터를 방출하는 액션 스트림을 Subject로 만들어보고 그때 발생할 수 있는 초기값 문제점을 해결해  보도록 하겠습니다.


rxjs를 이용해서 유저 액션을 처리하는 순서

  1. 먼저 유저 액션에 반응하기 위해 먼저 액션 스트림을 생성합니다. 액션 스트림을 만드는 방법 중 한가지는 Subject 또는 BehaviorSubject를 사용하는 것입니다.
  2. 그런 다음 액션 스트림을 데이터 스트림과 결합 합니다.  스트림의 결합은 combineLatest나 forkJoin과 같은 rxjs에서 제공해주는 생성 함수 혹은 연산자를 이용하게 됩니다.
  3. 마지막으로 액션이 발생할 때마다 액션 스트림에 값을 내보냅니다. 그러면 사용자 작업에 반응하는 옵저버블 파이프라인이 다시 실행됩니다.

이러한 과정을 통해 유저의 액션의 트리거로 방출된 데이터를 기반으로 데이터 스트림을 정제하여 원하는 데이터로 변환 표시할 수 있습니다. 이제 실습을 통해 액션 스트림을 만들어 인터렉션 처리를 하는 과정을 알아보도록 하겠습니다.


실습 목표 :  select box 선택 값으로 데이터 필터링 하기

실습 목표는 select box에서 선택되는 카테고리 선택에 따라 제품 목록을 필터링하여 화면에 표시하는 것입니다. 현재 화면은 아래와 같은 모습을 하고 있습니다.

상품 목록 화면에서 상품 목록과 카테고리 정보를 http get으로 가져와 데이터 스트림으로 만든 후 두 데이터 스트림을 결합하여 화면에 테이블로 표시하고 있습니다. 현재 카테고리가 유제품인 제품이 표시의 기본값으로 설정되어 있습니다. 화면에는 select box가 존재하여 각 카테고리를 고를 수 있습니다. 하지만 선택을 하여도 화면에는 아무런 변화가 없습니다. 따라서 카테고리가 유제품인 제품만 표시되고 있습니다.

select box의 선택이라는 액션이 발생할 때 방출하는 액션 스트림을 만들어 선택한 카테고리의 정보로 필터링하도록 수정해 보겠습니다.


위에서 언급한 세 단계 액션 데이터 생성, 스트림 결합, 액션 스트림으로 데이터 방출 순으로  코드를 완성하겠습니다. 

1. 액션 스트림 생성

먼저 액션 스트림을 생성합니다. 우리는 유저가 카테고리를 선택할 때마다 액션 스트림이 유저가 선택한 카테고리 id값을 방출하기를 원합니다.

액션 스트림 생성

number를 방출하는 Subject를 만들고 변수에 할당해 주었습니다. categorySelectedSubject는 다른 코드에서 Subject를 사용해서는 안 되므로 비공개로 정의하였습니다. 사실 이번 Subject는 서비스가 아닌 component에서 정의하고 있기 때문에 실제로 비공개로 선언할 필요는 없습니다. 하지만 Subject를 만들 때는 항상 private로 만드는 패턴을 따르는 것이 코드를 작성할 때 도움이 됩니다. Subject를 만든 다음 asObservable를 사용하여 Subject의 옵저버블을 노출합니다.

 

2. 데이터 스트림과 액션 스트림 결합

기존 화면 템플릿에서는 데이터 스트림인 products$ 옵저버블을 사용해 데이터를 구독하고 화면에 데이터를 출력했습니다. 이제 product$를 데이터 스트림으로만 설정하는 대신 데이터 스트림과 액션 스트림의 조합으로 설정하겠습니다.

스트림 결합

두 개의 스트림을 CombineLatest에 전달하고 있습니다. productsWithCategory$는 http get을 통해 생성되는 데이터 스트림입니다. categorySelectedAction$은 유저가 카테고리를 선택할 때 선택한 값을 방출하는 액션 스트림입니다. CobineLatest를 사용하면 카테고리를 선택할 때마다 데이터와 선택 값을 방출하는 옵저버블을 얻을 수 있습니다.

pipe처리의 map에서 방출된 배열 요소를 구조화합니다. 첫 번째 스트림은 제품의 배열을 방출하므로 첫 번째 배열 요소의 이름을 products로 지정하였습니다. 두 번째 스트림은 사용자가 셀렉트 박스에서 값을 카테고리를 선택할 때마다 selectedCategoryId를 내보냅니다. 따라서 두 번째 배열 요소의 이름을 selectedCategoryId로 지정하였습니다.

그런 다음 products 배열의 필터 메서드를 사용하여 목록을 필터링합니다. 이 처리를 통해 제품의 categoryId와 샐랙트 박스에서 방출된 id 값이 같은 데이터만 걸러지게 됩니다.

 

3. 액션 스트림 값 방출

마지막 단계는 유저의 액션이 발생할 때마다 액션 스트림에 값을 방출하는 것입니다.

템플릿 코드를 보면 select 박스의 값이 변할 때 선택한 값을 매개변수로 건네주며 onSelected를 호출하고 있습니다. 그럼 onSelected 메서드를 보겠습니다.

Subject의 next 메서드

onSelected 메서드에서는 Subject의 next 메소드를 사용하여 selectedCategoryId를 스트림으로 내보냅니다. next 메서드에서 +categoryId로 매개변수를 넘기고 있는데, ID를 숫자로 변환하기 위해서입니다.


결과 확인과 Subject의 초기값 문제점

브라우저에서 결과를 살펴보겠습니다.

초기 표기, 데이터 표시안됨

처음 초기 화면은 빈 페이지가 표시되고 있습니다. 셀렉트 박스에 Display All이 표시되고 있으므로 데이터가 모두 표시되어야 할 것 같은데 뭔가 이상하네요.

필터값 선택 후 데이터 표시됨

카테고리에서 김밥류를 선택하였습니다. 카테고리를 선택하면 필터링된 데이터가 잘 표시됩니다.

Display All 필터도 선택 후 작동

그리고 다시 Display All를 선택하면 모든 제품이 표시됩니다. 하지만 초기 페이지에 화면은 비어 있었습니다. 왜 이런 현상이 발생할까요?  그 이유는 작업 스트림에서 방출된 초기 값이 없기 때문입니다. CombineLatest는 각 입력 스트림이 방출될 때 까지는 값을 방출하지 않습니다. 초기 값이 없으면 액션 스트림이 방출되지 않습니다. 따라서 CombineLatest는 방출되지 않으므로 products$ 스트림은 방출되지 않으며 표시할 데이터가 존재하지 않게 됩니다. Subject대신에 초기값을 가지는 BehaviorSubject를 사용하면 이러한 문제점을 해결할 수 있습니다. 또는 startWith연산자를 파이프 처리에 사용해서 해결할 수도 있습니다.


Behavior Subject로 초기값 설정

아래는 BehaviorSubject로 수정한 코드입니다.

BehaviorSubject를 생성하면서 초기값으로 0을 넣어주고 있습니다. 이제 액션 스트림에서는 샐렉트 박스를 선택하기 전에도 초기값인 0을 방출하게 됩니다.

filter 처리를 보면 selectedCategoryId값이 0이라면 false판정이 되므로 모든 데이터가 true로 판정되어 데이터를 전부 가지게 됩니다. 따라서 모든 데이터가 화면에 표시되어집니다.

behaviorSubject로 기본값이 방출되어 초기데이터가 표시됨


 

여기까지 수고하셨습니다.

 

댓글