State는 보통 우리가 동적 데이터로 작업할 때 만들어진다. state는 object이고 컴포넌트의 데이터를 넣을 공간을 가지고 있다. 이 때, 데이터는 변경 가능하다
이번엔 함수형 컴포넌트 대신 클래스형 컴포넌트를 생성하자.
함수형 컴포넌트는 무엇인가를 return하고 screen에 표시하는 방식으로 작동하였다. 클래스형 컴포넌트는 React.Component
로 부터 확장되고 render 메소드 안에 작성한 내용이 screen에 표시되는 방식으로 작동한다. 이 때 react는 자동적으로 클래스 컴포넌트의 render 메소드를 실행한다.
<App.js>
import React from "react";
class App extends React.Component{
render(){
return <h1>Im a class component</h1>
}
}
export default App;
App 클래스는 React Component 에서부터 확장되었다. 따라서 App 클래스 또한 render 라는 메소드를 가지고 있다.
앞에서 말했듯 state는 object이고 바꾸고 싶은 데이터를 넣으면 된다. 주의할점은 {state}
가 아니라 {this.state.count}
라는 점이다.
<App.js>
import React from "react";
class App extends React.Component {
state = {
count: 0,
};
render() {
return
<h1>The number is : {this.state.count}</h1>;
}
}
export default App;
그러면 App 에서 어떻게 data의 값을 바꿀까?? 먼저 add와 minus 버튼을 만들어보자
<App.js>
import React from "react";
class App extends React.Component {
state = {
count: 0,
};
add = () => {
this.state.count = 1;
};
minus = () => {
this.state.count = -1;
};
render() {
return (
<div>
<h1>The number is : {this.state.count}</h1>
<button onClick={this.add}>add</button>
<button onClick={this.minus}>minus</button>
</div>
);
}
}
export default App;
add 와 minus 함수를 작성하고 Add 와 minus버튼 클릭 이벤트로 함수들을 매칭시켜주자.이 때, add()가 아니라 add 임에 주의하자add()는 즉시 실행되는 함수를 의미한다.
실행을 시켜보면 위와같은 메시지가 출력되면서 버튼을 눌러도 반응이 없을 것이다. state의 값을 직접 변경하지 말고 setState()를 사용하여 바꾸라고 하는 것이다.
그 이유는 setState 함수를 호출할 때,사용자가 view를 바꾸길 원하는 것을 react가 눈치채고 render를 refresh 해주기 때문이다. 만약 setState 함수를 호출하지 않으면 react는 사용자가 view를 refresh 해주길 원하는지 모르고 값을 변경하지 않게 된다.
요약하면 다음과 같다.
- setState 호출
- state를 refresh
- render 함수 호출
그럼 setState 함수를 호출하도록 변경해주고 결과를 확인해보자.
<App.js>
...
add = () => {
this.setState({ count: 1 });
};
minus = () => {
this.setState({ count: -1 });
};
...
export default App;
add버튼을 클릭시 숫자가 1, minus버튼을 클릭시 숫자가 -1로 변경됨을 확인할 수 있다. 개발자도구를 통하여 확인해보면 html 태그 속에서 1 , -1 부분만 변경되는 것을 볼 수 있는데, React는 앞서 말했던 virtual DOM 을 가지고 있기 때문에 필요한 부분만 업데이트를 할 수 있고 그 결과 매우 빠르게 변경이 가능하다.
그럼 우리가 원하는 방식으로 코드를 수정해 보자. add 버튼을 클릭시 count가 1 올라가고 minus 버튼을 클릭시 count가 1 내려가도록 변경하자
<App.js>
...
add = () => {
this.setState({ count: this.state.count+1 });
};
minus = () => {
this.setState({ count: this.state.count-1 });
};
...
export default App;
상식적으로 이렇게 짜는것이 보통이겠지만 이렇게 state를 사용하는 것은 옳지 못하다. 다음과 같이 코드를 수정하자
<App.js>
### ...
add = () => {
this.setState(current => ({ count: current.count+1 }));
};
minus = () => {
this.setState(current => ({ count: current.count-1 }));
};
...
export default App;
state를 set 할 때, 외부의 상태에 의존하지 않도록 작성하는 것이 좋다.
React.Component는 render 말고 생명주기와 관련된 함수들을 가지는데 이는 react가 컴포넌트를 생성하고 그리고 없애는 방법이다. 예를 들어, 컴포넌트가 생성 될 때, render하기 전 , render 된 후, 호출되는 함수들이 있다.
공부할 때마다 설명 추가
메소드를 바인딩하거나 state를 초기화하는 작업이 없다면, 해당 컴포넌트에는 생성자를 구현하지 않아도 된다.
생성자는 해당 컴포넌트가 마운트되기 전에 호출된다. 생성자를 구현할때는 먼저super(props)
를 호출해야 한다. 그렇지 않으면 this.props
가 생성자 내에서 정의되지 않아서 버그로 이어질 수 있다.
생성자는 보통 아래의 두 가지 목적을 위해서 사용한다.
this.state에 객체를 할당하여 지역 state를 초기화 인스턴스에 이벤트 처리 메소드를 바인딩
constructor()
내부에서 setState()를 호출하면 안된다. 컴포넌트에 지역 state가 필요하다면 생성자 내에서 this.state
에 초기 state 값을 할당하면 된다.
render()
메소드는 클래스 컴포넌트에서 반드시 구현돼야하는 유일한 메소드이다. render가 호출되면 this.props
와 this.state
값을 활용하여 아래의 것 중 하나를 반환해야 한다.
React 엘리먼트 배열과 Fragment Portal 문자열과 숫자 Boolean 또는 null
componentDidMount()
는 컴포넌트가 마운트된 직후, 즉 트리에 삽입된 직후에 호출된다. DOM 노드가 있어야 하는 초기화 작업은 이 메소드에서 이루어지면 된다.
componentDidMount()
는 외부에서 데이터를 불러와야 할 때, 네트워크 요청을 보내기 적절한 위치이다.
위와 동일
componentDidUpdate()
는 갱신이 일어난 직후에 호출된다. 이 메소드는 최초 렌더링에서는 호출되지 않는다.
컴포넌트가 갱신되었을 때 DOM을 조작하기 위하여 이 메서드를 활용하면 좋다. 또한 , 이전과 현재의 props를 비교하여 네트워크 요청을 보내는 작업도 이 메소드에서 이루어지면 된다.
상위에서 내려온 prop을 그대로 state에 저장하는 것은 좋지 않으며, 그 대신 prop을 직접 사용하는 것이 좋다.
componentWillUnmount()
는 컴포넌트가 마운트 해제되어 제거되기 직전에 호출된다. 이 메소드에서 타이머 제거, 네트워크 요청 취소등 정리 작업을 수행하면 된다.
출처 : Do it! 리액트 프로그래밍 정석 / 노마드 코더