2.3 클래스 컴포넌트와 함수 컴포넌트
2.3.1 클래스 컴포넌트
클래스 컴포넌트의 생명주기 메서스
mount, update, unmount 세 가지로 크게 나눌 수 있다.
render()
컴포넌트가 UI를 렌더링하기 위해서 쓰인다. 렌더링은 마운트와 업데이트 과정에서 생기게 된다. this.setState를 호출할 수 없다.
componentDidMount()
클래스컴포넌트가 마운트되고 준비 됐다면 그 다음으로 호출되는 생명주기이다.
this.setState()로 state값을 변경하는 것이 가능하다. state가 변경되는 작업은 실제로 UI를 업데이트하기 전에 실행되어 사용자가 변경되는 것을 눈치챌 수 없게 만든다.
하지만 해당 함수는 성능에 문제를 일으킬 수 있기 때문에 일반적으로 state를 다루는 것은 생성자에서 하도록 하자. ( 웬만하면! )
componentDidUpdate()
컴포넌트 업데이트가 일어난 이후 바로 실행된다. 일반적으로 state나 props의 변화에 따라 DOM을 업데이트 하는등에 쓰인다.
componentWillUnmount()
컴포넌트가 언마운트되거나 더 이상 사용되지 않기 직전에 호출된다. 메모리 누수나 불필요한 작동을 막기 위한 클린업 함수를 호출하기 위한 최적의 위치다. this.setState를 호출할 수 없다.
shouldComponentUpdate()
state나 props의 변경으로 리액트 컴포넌트가 다시 리렌더링 되는 것을 막는 용도로 사용된다. 특정한 성능 최적화 상황에서만 고려해야한다.
Component 와 PureComponent
정리하자면 component 는 state 자체에 대한 비교를 한다.
pureComponent 는 state의 얕은 복사를 통해 업데이트를 해주기 때문에 state가 객체와 같이 복잡한 구조의 데이터라면 변경을 감지하지 못해 제대로 작동하지 않는다.
따라서 pureComponent는 적재적소에 사용하여 활용해야한다.
static getDerivedStateFromProps()
이제는 사라진 componentWillReceiveProps를 대체할 수 있는 메서드다. render()를 호출하기 직전에 호출되며 static으로 선언되어 있어 this에 접근할 수 없다.
getSnapShotBeforeUpdate()
componentWillUpdate()를 대체할 수 있는 메서드다. DOM이 업데이트되기 직전에 호출된다. DOM에 렌더링되기 전에 윈도우 크기를 조절하거나 스크롤 위치를 조정하는 등의 작업을 처리하는데 사용된다.
정리
에러를 처리 하는 메서드
getDerivedStateFromError() , componentDidCatch 두 가지가 존재한다.
둘의 차이는 실행이 되는 시기인데 getDerivedStateFromError() 는 위 그림의 "render단계"에서 실행이 되기 때문에 미리 정의해 둔 state 값을 반환하는 용도 이외에는 사용하면 안된다. 만약 console을 찍고 싶다거나 부수 효과를 원한다면 componentDidCatch를 사용해서 처리해줘야 한다.
클래스 컴포넌트를 사용하지 않는 이유
데이터의 흐름을 추적하기 어렵다.
애플리케이션 내부 로직의 재사용이 어렵다.
사용하려하면 할수록 고차컴포넌트와 prop 이 많아지는 래퍼지옥에 빠지게 된다.
기능이 많아질수록 컴포넌트의 크기가 커진다.
클래스는 함수에 비해 상대적으로 어렵다.
코드 크기를 최적화하기 어렵다.
핫 리로딩을 하는 데 상대적으로 불리하다.
핫리로딩 : 코드에 변경 사항이 발생했을 때 앱을 다시 시작하지 않고서도 해당 변경된 코드만 업데이트하여 변경 사항을 빠르게 적용하는 기법
클래스형 컴포넌트는 render 수정시 instance를 새로 생성하게 되며 state 값이 초기화 되기 때문에 핫리로딩에 불리하다. 함수형 컴포넌트는 state값을 함수가 아닌 클로저에 넣어놓기 때문에 다시 실행되어도 state값을 잃지 않는다.
2.3.3 함수 컴포넌트 vs 클래스 컴포넌트
생명주기의 부재
클래스 컴포넌트는 생명주기가 눈에 보이지만 함수 컴포넌트는 생명주기라는 것이 없기 때문에 만약 생명주기를 사용하고 싶다면 클래스 컴포넌트를 사용해야 한다.
함수 컴포넌트 또한 useEffect를 사용해서 생명주기를 비슷하게 흉내낼 수 있지만 똑같다라는 말이 절대 아니다.
함수 컴포넌트와 렌더링된 값
setTimeout 과 같은 함수를 사용했을 때 클래스 컴포넌트와 함수 컴포넌트는 다르게 작동하게 된다.
3000ms 로 time 을 설정해주고 받아오는 prop 값을 실행함수에서 콘솔로 찍어주는 함수가 있다. onClick 이벤트로 실행 되는 이 setTimeout 은 prop이 중간에 바뀌게 되면 어떻게 작동할까?
함수 컴포넌트는 3초 뒤에 변경되기 전의 prop값을 콘솔로 찍어 줄 것이다.
하지만 클래스 컴포넌트는 변경 된 prop을 콘솔로 찍어줄텐데 이는 클래스 컴포넌트의 prop이 this에 바인딩 되어있기 때문이다.
클래스 컴포넌트를 공부해야할까?
함수형에 자신이 있다면 한번 해보자. 역사를 알아야 미래도 알 수 있으니까!