state
동적인 데이터를 다룰 때는 state라는 개념을 사용한다. 빠르게 예시를 통해 넘어가보자.
import React, { Component } from 'react';
class Counter extends Component {
state = {
number: 0
};
handleIncrease() { }
handleDecrease() { }
render() {
return (
<div>
<h1>값 올려보기</h1>
<div> 값: {this.state.number} </div>
<button onClick={this.handleIncrease}>+</button>
<button onClick={this.handleDecrease}>-</button>
</div>
);
}
}
export default Counter;
새로운 컴포넌트를 하나 생성해보자. state 객체 안에는 number가 0으로 기본적으로 할당되어있다. 값을 증가시켜주는 함수들을 마저 작성해보겠다.
import React, { Component } from 'react';
class Counter extends Component {
state = {
number: 0
};
handleIncrease() {
this.state.number = this.state.number + 1;
}
handleDecrease() {
this.state.number = this.state.number - 1;
}
render() {
return (
<div>
<h1>값 올려보기</h1>
<div> 값: {this.state.number} </div>
<button onClick={this.handleIncrease}>+</button>
<button onClick={this.handleDecrease}>-</button>
</div>
);
}
}
export default Counter;
이렇게 작성했을 경우에는 에러가 발생할 것이다.
이게 무슨 에러냐면 this.state.number에서 state가 undefined라는 뜻이다. state에 대해 직접 값을 변경하려는 것은 권장되지 않고 리액트에서 상태를 업데이트하는 유일한 방법이다. 그렇기에 setState라는 함수를 사용해야 되겠다.
import React, { Component } from 'react';
class Counter extends Component {
state = {
number: 0
};
handleIncrease() {
this.setState({
number: this.state.number + 1
});
}
handleDecrease() {
this.setState({
number: this.state.number - 1
});
}
render() {
return (
<div>
<h1>값 올려보기</h1>
<div> 값: {this.state.number} </div>
<button onClick={this.handleIncrease}>+</button>
<button onClick={this.handleDecrease}>-</button>
</div>
);
}
}
export default Counter;
따라서 다음과 같이 작성해주어야겠다. setState를 사용해야하는 이유는 비동기적으로 setState가 상태를 업데이트한다. 그리고 그 변경 사항을 리액트의 렌더링 시스템에 알려주어 리액트는 상태 변화를 감지하고 컴포넌트를 재랜더링한다.
근데 이렇게 해도 에러는 날 것이다.
setState가 undefined라고 나오는데 이는 this가 undefined이기 때문이다. 버튼증가 함수를 클릭했을 때의 이벤트가 발생하면 this가 undefined가 된 것인데 다음과 같이 처리해야 한다.
import React, { Component } from 'react';
class Counter extends Component {
state = {
number: 0
};
constructor(props) {
super(props);
this.handleIncrease = this.handleIncrease.bind(this);
this.handleDecrease = this.handleDecrease.bind(this);
}
handleIncrease() {
this.setState({
number: this.state.number + 1
});
}
handleDecrease() {
this.setState({
number: this.state.number - 1
});
}
render() {
return (
<div>
<h1>값 올려보기</h1>
<div> 값: {this.state.number} </div>
<button onClick={this.handleIncrease}>+</button>
<button onClick={this.handleDecrease}>-</button>
</div>
);
}
}
export default Counter;
생성자 같은 느낌의 무언가가 생성되었는데 이를 정리하면 다음과 같다.
constructor는 클래스 컴포넌트의 인스턴스가 생성될 때 호출되는 특별한 메소드이다. 이 내부에서 컴포넌트의 state와 메소드 바인딩을 설정할 수 있다.
super()은 부모 클래스의 생성자를 호출하는 코드이다. 현재 Counter라는 클래스는 React.Component 클래스에 상속받고 있다. 즉, 부모 클래스를 호출해야 this.props에 접근할 수 있고 state와 props를 제대로 사용할 수 있게 된다.
결과적으로 this를 사용하기 위해서는 super() 메소드를 통해 부모 클래스(리액트 컴포넌트)를 호출하여 this에 접근해 state 또는 props를 사용할 수 있다. 그리고 이 this를 해당 함수와 바인딩(bind)하여 this와 연결할 수 있도록 한다.