본문 바로가기
블로그 이미지

방문해 주셔서 감사합니다! 항상 행복하세요!

  
   - 문의사항은 메일 또는 댓글로 언제든 연락주세요.
   - "해줘","답 내놔" 같은 질문은 답변드리지 않습니다.
   - 메일주소 : lts06069@naver.com


앵귤러, 리엑트, 뷰/앵귤러(Angular)

RXJS, Subscribe에 대한 중요 (무한구독의 방지)

야근없는 행복한 삶을 위해 ~
by 마샤와 곰 2019. 4. 29.

 

 

앵귤러를 활용하여 개발하다보면 심심치 않게 나오는 메소드가 subscribe로 시작하는 메소드 이다.

subscribe는 구독하다 라는 의미인데, 기능 또한 동일한 기능을 발휘한다.

대부분 subscribe로 시작되는 메소드는 Rxjs를 기반으로 만들어졌다.

파이어 베이스에 접속해서 데이터를 가져오는 모습을 예로 살펴 보자.

 private itemsCollection: AngularFirestoreCollection<any>;  //조회한 대상이 담긴 리스트

 selectList(){  //리스트에 담는 메소드
   this.itemsCollection = this.DataBase.collection<any>('조회대상', (ref) =>ref);
 }

 alterItem(changeItem : any){  //데이터를 바꾸는 메소드
    this.itemsCollection.stateChanges().pipe(
      map(
          changes => { return changes.map(a => {
            const data = a.payload.doc.data() as any;
            const ID = a.payload.doc.id;
            if(data.idx == changeItem.idx){
              this.itemsCollection.doc(ID).set(changeItem);  //수정
            }
            return data;
          });
        }
      )).subscribe();  
  }

리스트에 담는 메소드를 활용하여 파이어베이스에서 데이터를 가져왔다고 하자.

그리고 사용자가 데이터를 수정해서 alterItem이라는 메소드를 호출해서 데이터를 수정했다고 하자.

* 위 alterItem이라는 메소드의 내용은 angularfire2에서 제공하는 내용과 거의 동일하다

수정한 데이터가 반영이 되었다고 한 뒤에 다시한번 수정버튼을 누르면 엄청난 일이 발생한다.

수정하는 행위가 무한반복이 되는 현상을 볼 수 있다. 나는 한번만 눌렀는데 왜 계속 수정하는 것인가?

이를 이해하려면 RxJs에 대해서 어느정도 이해도가 필요하다.

import { Subject } from 'rxjs';

const sub = new Subject();

sub.subscribe(console.log);
sub.next(1); // 1이 출력됨
sub.subscribe(console.log);
sub.next(2); // 2가 두번 출력됨

위의 예제코드는 Rxjs의 기능에 대해서 아주 간단하게 설명한 예제코드 이다. subscribe 의 기능은 내가 바라보고있는 주제에 대해서 어떠한 이벤트가 발생함에 따라서 그 행위를 처리하는 함수이다.

구독을 시작하게된 행위는 변경된 이벤트에 대해서 계속 반응하게 된다.

즉, 한번 구독을 시작하면(subscribe) 따로 중지를 시키지 않으면 계속 구독하게 되는 것이다.

다시 맨 처음 보았던 소스코드를 살펴보자.

해당 소스코드를 보면 alterItem이라는 메소드가 호출되면 subscribe를 통해 구독하는 횟수가 늘어난다. subscribe가 계속 실행되면 alterItem을 누른 횟수 만큼 구독행위가 계속늘어나게 되는 것이다.

수정을 두번누르게되면..구독을 2번하라는 의미이다.

한번 구독했는데 다시 구독하라고 명령을 보낸 셈이다.

처음구독하는 행위가 데이터를 바꾸면 그다음 구독행위가 데이터를 다시바꾸고..

다시바꾼 데이터를 처음데이터가 바뀐줄 알고 다시바꾸고...

이러한 행위가 무한루프가 되어서 엉망인 코드가 되어 버리는 것이다.

이를 수정하려면 구독하는 행위에 대해서 멈춤이 필요하다.

맨 처음 소스코드를 아래처럼 수정해보자.

private itemsCollection: AngularFirestoreCollection<any>;  //조회한 대상이 담긴 리스트

 selectList(){  //리스트에 담는 메소드
   this.itemsCollection = this.DataBase.collection<any>('조회대상', (ref) =>ref);
 }
 private subscription : any;  //구독 객체

 alterItem(changeItem : any){  //데이터를 바꾸는 메소드

    if(this.subscription != undefined && this.subscription != null){
      if(!this.subscription.closed){
        this.subscription.unsubscribe();  //무한 구독 방지
      }
    }
  
    this.subscription = this.itemsCollection.stateChanges().pipe(  //구독행위를 담자.
      map(
          changes => { return changes.map(a => {
            const data = a.payload.doc.data() as any;
            const ID = a.payload.doc.id;
            if(data.idx == changeItem.idx){
              this.itemsCollection.doc(ID).set(changeItem);  //수정
            }
            return data;
          });
        }
      )).subscribe();  
  }

Rxjs에서 Subscribe를 실행하면 Subscription이라는 객체를 되돌려준다. 해당객체에는 현재 구독중인 상태 및 중지를 할 수 있는 기능이(unsubscribe)존재한다.

Rxjs를 활용한 모듈을 만나서 subscribe로 시작되는 메소드를 호출한 경우, 필요에 따라서 위 예제처럼 unsubscribe 메소드를 호출해서 무한 호출행위에 대해서 고려해야될 필요가 있는 것이다.

반응형
* 위 에니메이션은 Html의 캔버스(canvas)기반으로 동작하는 기능 입니다. Html 캔버스 튜토리얼 도 한번 살펴보세요~ :)
* 직접 만든 Html 캔버스 애니메이션 도 한번 살펴보세요~ :)

댓글