TIL 220222 Class 안에서 binding을 해줘야 하는 이유, 방법

Minju Kim·2022년 2월 22일

TIL

목록 보기
5/5
post-thumbnail

This is why we need to bind event handlers in Class Components in React
Why do we need to bind methods inside our class component’s constructor?

게임을 만드는 동안 문제가 하나 발생했다.
class의 constructor안에서 eventhandler를 추가해주었는데, 추가해 준 그 EventHandler가 작동하지 않는 것이다! 문제가 무엇일까?
👉 그것은 바로 '함수를 메서드가 아닌 함수로 부를때, this가 context를 잃어버리기 때문이다!!'

이를 이해하기 위해서는 아래의 코드를 먼저 살펴봐야 한다.

var x = 10;
let foo = {
  x: 90,
  getX: function() {
    return this.x;
  }
};

foo.getX(); // prints 90

let xGetter = foo.getX;

xGetter(); // prints 10;

위의 예제에서 foo.getX()는 메서드로 불렸기 때문에 이 경우 this는 foo객체를 의미하여 90을 리턴했다. 그러나 foo.getX에 연결된 함수를 XGetter라는 변수에 그 주소값을 저장한 후, 변수를 통해 함수를 호출한 경우, 즉 함수를 메서드가 아닌 함수로 호출한 경우, this는 문맥을 잃어버리기 때문에 전역변수x의 값인 10을 리턴했다.

이런 현상이 일어나는 대신, 90을 똑같이 리턴하고 싶은 경우, this를 다음과 같이 바인딩 해주면 된다.

let getFooX = foo.getX.bind(foo);
getFooX(); // prints 90

즉, 그 문맥을 까먹지 않게 this 바인딩을 해 주는 것이다.

👶그렇다면, 자 이제 다시 class로 돌아와서 살펴보자!

 <button> Click Me!</button>
 class Game {
            constructor(){
                this.player = 'minju';
                this.level = 10;
                this.button = document.querySelector('button');
                this.button.addEventListener('click', this.onClick);
            }
            
            onClick(){
                console.log(this.level);
            }

        }


        const player1 = new Game;

자, Click Me 버튼을 클릭했다. 그 순간 이벤트리스너가 player1 객체의 onClick인 console.log(this.level)을 실행하는데...! this가 가리키는 것은 strict mode에서 undefined라고 호출된다!!! 메서드 호출이 아닌 함수호출이기 때문에 this가 문맥을 잃어버린 것!

이를 바꿔주려면 총 세 가지 방법을 사용할 수 있다.
1) 콜백으로 가져오는 클래스 내부의 함수를 변수로 바꿔준 후, 화살표 함수로 바꿔주는 방법
2) 이벤트리스너 안에서 애초에 화살표 함수를 쓰는 방법
3) bind()를 통해 this 바인딩을 해 주는 방법.

1번부터 살펴보면, 다음과 같이 변경할 수 있겠다.

방법 1. 콜백으로 가져오는 클래스 내부의 함수를 변수로 바꿔준 후, 화살표 함수로 바꿔주는 방법

        class Game {
            constructor(){
                this.player = 'minju';
                this.level = 10;
                this.button = document.querySelector('button');
                this.button.addEventListener('click', this.onClick);
            }
            
          // 다음을 주목!!
            onClick = () => {
                console.log(this.level);
            }
        }

방법 2. 이벤트 리스너 안의 함수를 화살표 함수를 사용하는 방법

class Game {
    constructor(){
     this.player = 'minju';
     this.level = 10;
     this.button = document.querySelector('button');
                this.button.addEventListener('click', (event) => this.onClick(event));
            }
            
    onClick () {
       console.log(this.level);
    }
}

방법3. bind()를 통해 콜백함수에 this를 바인딩하는 방법

     class Game {
       constructor(){
         this.player = 'minju';
         this.level = 10;
         this.button = document.querySelector('button');
         this.onClick = this.onClick.bind(this);
         this.button.addEventListener('click', this.onClick);
            }
            
       onClick () {
         console.log(this.level);
       }
    }

위 세가지 방법 중 가장 좋은 것은, 방법1! 가독성이 좋고, 그 의미를 이해하기 편하기 때문!

profile
⚓ A smooth sea never made a skillful mariner

0개의 댓글