일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 |
- SSR
- 달리기경주
- Firebase
- React
- 겹치는 선분의 길이
- Next
- 생명주기
- JS
- debounce
- 배열
- Recoil
- 투두리스트
- 넥스트
- NextJS
- JavaScript
- Redux
- customModal component 만들기
- next-pwa
- programmers
- 리엑트
- 파이어베이스
- react-query
- lifecycle
- 리액트
- todolist
- csr
- google firebase
- useMutation
- 리덕스
- 자바스크립트
- Today
- Total
끄적끄적
[React] 자주 쓰이는 React 생명 주기(Class편) 본문
리액트의 컴포넌트들은 다음과 같이 세 단계를 거치게 됩니다. 초기화, 업데이트, 소멸.
각 단계에서 호출되는 메서드를 생명 주기 메서드 라고 합니다.
React 입문자가 사이트를 만들어 보게되면 생명주기를 잘 이용하지 않을 뿐더러, 중요성을 잘모르고 만들다보면
꼭! 어느순간 뒤통수를 쎄게 맞는 순간이 있습니다..
내 뒤통수가 푹 파인 이유...
요즘은 React Hook을 이용한 Functional Component가 대세라고 하지만 아직까지 어느 부분에 있어서는 class형 컴포넌트를 사용함에 이점이 있고, 사용하는 사람들도 은근 많은것 같습니다.
그럼 자주보이는 React 생명주기를 하나씩 살펴보겠습니다!
■ constructor
constructor 메서드 작성이 필요한 대표적인 예는 초기 속성값으로부터 상탯값을 만드는 경우입니다!
기본 구조는 constructor(props) 이며 props 매개변수는 컴포넌트의 기본 속성값이 적용된 상태로 호출됩니다.
constructor 메서드 내부에서 반드시 super 함수를 호출해야 React.Componet클래스의 constructor 메서드가 호출됩니다.
class App extends React.Component {
constructor(props){
super(props);
this.state = {
fromProps : props.attr
}
}
이렇게 상탯값을 직접 할당하는 것은 constructor 메서드에서만 허용됩니다.
다른 생명주기에서는 setState를 이용해 state값을 변경할 수 있습니다.
+constructor에서의 setState 메서드는 무시된다. (setState는 마운트 이후에만 유효하기에)
■ getDerivedStateFromProps
getDerivedStateFromProps 메서드는 속성값을 이용해서 새로운 상탯값을 만들 때 사용됩니다.
이 메서드는 render 호출 직전에 호출되며, 메서드의 구조는 다음과 같습니다.
static getDerivedStateFromProps(props, state)
이 메서드는 시간에 따라 변하는 속성값으로부터 상탯값을 계산하기 위해 추가됐습니다.
정적 메서드 이기 때문에 함수 내부에서 this 객체에 접근할 수 없고, 오로지 속성값과 상탯값을 기반으로 새로운 상탯값을 만들어 냅니다.
(보통 애니메이션과 관련된 속성값으로 부터 상탯값을 계산할때 쓰인다. 스크롤 Y축 위치 저장 용도... 등)
Q) 이전 속성값을 매개변수로 넣지 않은 이유?
A) 최초 호출시 이전 속성값은 null 이므로 항상 검사해는 번거로움, 쓸데 없는 메모리 낭비
이 메서드가 유의미한 경우는 이전 속성값과 이후 속성값 모두에 의존적인 상탯값이 필요한 경우이다.
class App extends React.Component {
state = {
// ...
prevSpeed : this.props.speed,
isMovingFaster : false,
};
static getDerivedStateFromProps(props, state){
if(props.speed !== state.prevSpeed){
return {
isMovingFaster : state.prevSpeed < props.speed,
prevSpeed : props.speed,
};
}
return null;
}
}
■ render
화면에 보여질 render 메서드의 반환값의 내용을 결정합니다.
렌더함수는 순수함수(pure function)으로 작성되야 합니다. 따라서 다음과 같은 내용을 명심!
● 렌더 함수 내부에서 setState를 호출하면 안된다.
● 렌더 함수의 반환값은 속성값과 상탯값만으로 결정되어야 한다.
● 부수 효과를 발생시키면 안된다. (필요하면 다른 생명주기 메서드에서 하면된다.)
render 메서드가 반환할 수 있는 형태
return <MyComponent />; //컴포넌트 호출
<p>하이</p>; //HTML요소
'안녕하세요'; //문자열
123; //숫자
[<p key="a">안녕</p>, <p key="b">반가워</p>]; //배열
(
<React.Fragment>
<p>하이</p>
<p>방가</p>
</React.Fragment>
); // 리액트 프래그먼드를 사용하면 내부 리액트 요소에 key속성을 부여하지 않아도 된다.
null;
false; // null이나 bool을 반환하면 화면에 아무것도 랜더링하지 않는다.
ReactDOM.createPortal(<p>하이</p>, domNode); //리액트 포털을 사용하면 컴포넌트의 현재 위치와는 상관없이 특정 돔 요소에 렌더링 가능
■ componentDidMount
componentDidMount 메서드는 render 메서드의 첫 번째 반환값이 실제 돔에 반영된 직후 호출됩니다.
따라서 render 메서드에서 반환한 리엑트 요소가 돔에 반영되어야 알 수 있는 값을 얻을 수 있습니다. (ex, 화면의 가로길이..)
componentDidMount 메서드에서 setState메서드를 호출하면 다시 렌더링을 합니다.
따라서, API호출을 통해 데이터를 가져올 때 적합! setState 메서드가 마운트 이후에만 동작하기 때문이다.constructor에서 API호출 후 setState 메서드를 호출하면 데이터가 저장되지 않을 수 있다
but, constructor가 먼저 호출되므로 API 호출 결과를 더 빨리 받아올 수 있는 사실에는 변함이 없다.
그래서 다음과 같이 프로미스 를 이용하여 효율적으로 코드를 작성할 수 있다.
class App extends React.Component {
constructor(props){
super(props);
this.dataPromise = requestData();
}
componentDidMount(){
this.dataPromise.then(data => this.setState({ data }));
}
}
■ shouldComponentUpdate
이 메서드는 성능 최적화를 위해 존재합니다.
shouldComponentUpdate(nextProps, nextState)
위와같은 구조를 갖으며 bool 타입을 반환합니다.
만약 true를 반환하면 render 메서드를 호출하며,
false를 반환하면 업데이트 단계는 여기서 멈추게 됩니다.
개발자는 속성값과 상탯값을 기반으로 참,거짓을 반환하는 코드를 작성하여 render 실행여부를 결정할 수 있습니다.
class App extends React.Component{
shouldComponentUpdate(nextPorps, nextState){
const { price } = this.state;
return price !== nextState.price; //상탯값이 변경된 경우에만 return true
}
}
■ componentDidUpdate
업데이트 단계에서 마지막으로 호출되는 생명주기 메서드입니다.
componentDidUpdate(prevPorps, prevState, snapshot)
위의 구조를 갖으며 가상돔이 실제 돔에 반영된 후 호출됩니다.
따라서 새로 반영된 돔의 요솟값을 가장 빠르게 가져올 수 있는 메서드입니다.
다음 코드는 사용자가 변경되면 친구 목록을 가져오는 API를 호출하는 예시 코드입니다.
class App extends React.Component {
componentDidUpdate(prevProps){
const { usser } = this.props;
if(prevProps.user.id !== user.id){
requestFriends(user).then(friends => this.setState({ friends }));
}
}
}
■ componentWillUnmount
이 메서드는 소멸 단계에서 호출되는 유일한 생명 주기 메서드입니다.
끝나지 않는 네트워크 요청을 취소, 타이머 해제, 구독 해체 등의 작업을 처리하기 좋습니다.
componentDidMount가 호출되면 componentWillUnmount가 호출되는 것은 보장됩니다.
따라서 componentDidMount에서 구독하고, componentWillUnmount에서 구독 해제하는 코드가 자주 사용됩니다.
다음 코드는 이벤트 처리 등록, 해제하는 예제 코드입니다.
class App extends React.Component {
componentDidMount() {
const domNode = document.getElementById('someNode');
domNode.addEventListener('change', this.onChange);
}
componentWillUnmount(){
const domeNode = document.getElementById('someNode');
domNode.removeEventListener('change', this.onChage);
}
}
지금까지 React에서 사용되는 생명주기 중 몇가지를 다뤄보았습니다.
프로그램이 복잡해질수록, 상호작용이 많이 필요할수록 생명주기에 대한 이해가 중요한 것 같습니다.
뒤통수가 납작해져가며 배워가는게 정석이겠죠..ㅎㅎ
-인사이트 [실전 리액트 프로그래밍] 참조
'React' 카테고리의 다른 글
[React+Redux]간단하게 만들어보는 Todolist(1) (0) | 2020.11.27 |
---|---|
[상태관리라이브러리] Redux(리덕스) (0) | 2020.11.25 |
[React] 자주 쓰이는 React 생명 주기(함수형편, useEffect) (0) | 2020.11.25 |
[React + Firebase] OAuth 소셜 로그인 (0) | 2020.11.25 |
[React + Firebase] 호스팅(Hosting) (0) | 2020.11.25 |