ES6 클래스를 사용하여 컴포넌트를 정의할 때, 일반적인 패턴은 이벤트 핸들러를 클래스의 메서드로 만드는 것입니다.
class Toggle extends React.Component {
constructor(props) {
super(props);
this.state = {isToggleOn: true};
}
//클래스의 매서드
handleClick() {
this.setState(prevState => ({
isToggleOn: !prevState.isToggleOn
}));
}
render() {
return (
<button onClick={this.handleClick}>
{this.state.isToggleOn ? 'ON' : 'OFF'}
</button>
);
}
}
ReactDOM.render(
<Toggle />,
document.getElementById('root')
);
작성된 예제로는 버튼을 클릭하면 isTogleOn이 false로 변할 것으로 예측이 됩니다. 하지만 실제로 실행을 해보면 실행되지 않고 아래와 같은 에러가 출력되는 것을 확인할 수 있습니다.
setState가 실행될 때 this가 undefined이라고 이야기를 하고 있습니다. 한번 console.log를 실행해 확인해보도록 하겠습니다.
handleClick() {
console.log('handleClick', this)
this.setState(prevState => ({
isToggleOn: !prevState.isToggleOn
}));
}
componentDidMount() {
console.log('componentDidMount', this)
}
render() { //render()을 붙여줘야지만 렌더가 됩니다.
console.log('render', this)
return (
<button onClick={this.handleClick}>
{this.state.isToggleOn ? 'ON' : 'OFF'}
</button>
);
render
에서도 componentDidMount
에서도 this는 Toggle컴포넌트를 잘 가르키고 있지만, 버튼을 클릭하면 undefined가 출력되는 것을 확인할 수 있습니다.
JavaScript에서 this는 함수를 어떻게 호출되느냐에 따라서 참조가 달라지게 됩니다. 현재는 콜백안에서의 this 사용하고 있기 때문에 다른 클래스의 this를 참조하지 못합니다.
따라서 contructor
안에서 this.handleClick = this.handleClick.bind(this);
를 통해 this를 바인딩 시켜줘야합니다.
class LoggingButton extends React.Component {
// 이 문법은 `this`가 handleClick 내에서 바인딩되도록 합니다.
// 주의: 이 문법은 *실험적인* 문법입니다.
handleClick = () => {
console.log('this is:', this);
}
render() {
return (
<button onClick={this.handleClick}>
Click me
</button>
);
}
}
class LoggingButton extends React.Component {
handleClick() {
console.log('this is:', this);
}
render() {
// 이 문법은 `this`가 handleClick 내에서 바인딩되도록 합니다.
return (
<button onClick={() => this.handleClick()}>
Click me
</button>
);
}
}
하지만 화살표함수의 경우 렌더링될 떄마다 다른 콜백이 생성되기 때문에 클래스 컴포넌트에서 사용을 지양하고 있습니다.
따라서 생성자 안에서 바인딩하거나 클래스 필드 문법을 사용하는 것을 권장합니다.