리액트 에서의 this
리액트 클래스 컴포넌트에서 THIS를 사용하기 위해 바인딩을 해야 하는 이유
단계적으로 살펴 보자
1. JavaScript에서 this는 호출 방식에 따라 결정 된다.
자바스크립트에서 함수 내의 this는 함수 호출 방식에 따라 다르다.
- 일반 함수 호출 : this는 undefined(strict mode)또는 전역 객체(window 또는 global) 참조
- 메서드 호출 : 호출된 객체를 참조
- 이벤트 핸들러 : 기본적으로 이벤트를 트리거한 DOM 요소를 참조
리액트의 클래스 컴포넌트에서 메서드가 이벤트 핸들러로 전달될 때 메서드와 클래스 인스턴스 간의 연결이 끊어질 수 있다. 따라서 this가 undefined가 되어 오류가 발생할 수 있다.
2. 리액트 클래스 컴포넌트에서의 문제
class MyComponent extends React.Component {
constructor() {
super();
this.state = { count: 0 };
}
handleClick() {
console.log(this.state.count); // TypeError: Cannot read properties of undefined
}
render() {
return <button onClick={this.handleClick}>Click Me</button>;
}
}
위 코드에서 버튼을 클릭하면 handleClick이 호출되지만, 이때의 this는 MyComponent 인스턴스를 참조하지 않고 undefined가 된다.
이유는 handleClick 메서드가 이벤트 핸들러로 호출될 때, 메서드의 컨텍스트(this가 가르키는 대상)가 변경 되었기 때문이다.
3. 바인딩으로 this를 명시적으로 고정
위 2번의 문제를 해결하기 위해 this를 명시적으로 컴포넌트 인스턴스에 바인딩해야 한다.
class MyComponent extends React.Component {
constructor() {
super();
this.state = { count: 0 };
this.handleClick = this.handleClick.bind(this); // 바인딩
}
handleClick() {
console.log(this.state.count); // 정상적으로 작동
}
render() {
return <button onClick={this.handleClick}>Click Me</button>;
}
}
bind메서드를 사용하여 handleClick 메서드가 항상 MyComponent의 인스턴스를 참조하도록 만든다.
4. 바인딩을 생략하는 방법 : 화살표 함수
바인딩을 사용하지 않고 해결할 수 있는 방법이 있다.
화살표 함수를 사용하는 것이다.
화살표 함수는 자신만의 this를 가지지 않고, 상위 스코프의 this를 자동으로 참조한다.
class MyComponent extends React.Component {
constructor() {
super();
this.state = { count: 0 };
}
// 화살표 함수 사용
handleClick = () => {
console.log(this.state.count); // 정상적으로 작동
};
render() {
return <button onClick={this.handleClick}>Click Me</button>;
}
}
이 방식은 더 갈결하고, 최근 리액트 프로젝트에서는 화살표 함수를 사용하는 것이 일반적이다.
정리
- 리액트 클래스 컴포넌트에서 메서드가 이벤트 핸들러로사용될 때, this가 메서드 호출 문맥에 따라 다르게 동작한다.
- 이를 해결하기 위해 bind(this)를 통해 this를 명시적으로 고정 하거나, 화살표 함수를 사용한다.
- 함수 컴포넌트와 훅이 등장하면서 클래스 컴포넌트 사용 빈도가 줄고 있지만, 클래스 컴포넌트를 사용할 때는 이런 바인딩 개념이 중요하다.
bind 메소드에 대한 포스팅 참고
https://moo-you.tistory.com/571
https://moo-you.tistory.com/1091
화살표 함수에 대한 포스팅 참고
https://moo-you.tistory.com/489