Class Component
constructor()
컴포넌트가 초기화되는 시점에 호출
constructor 내부에서 state를 초기화 할 수 있음
super()
를 이용하여, 상속받은 상위 컴포넌트에 접근할 수 있도록 도와줌
state
클래스형 컴포넌트 내부에서 관리하는 값
값은 항상 객체여야만 함
변화가 있을 때마다 리렌더링이 발생함
props
컴포넌트에 속성을 전달하는 용도
메서드
constructor에서 this바인딩
일반 함수로 호출 시 this에 전역 객체가 바인딩(strict모드에서는 undefined)되므로 bind를 활용해 강제로 this를 바인딩 해야 함.
화살표 함수를 사용
실행시점이 아닌 작성시점에 this가 상위 스코프로 결정되는 화살표 함수를 사용하면 바인딩 하지 않아도 됨.
렌더링 함수 내부에서 함수를 새롭게 만들어 전달
매번 렌더링이 일어날 떄마다 새로운 함수를 생성해서 할당하게 되므로
최적화를 수행하기 어려움
리액트 생명주기(Life Cycle)
생명주기 메서드 실행시점
마운트(mount) : 컴포넌트가 생성되는 시점
업데이트(update) : 이미 생성된 컴포넌트가 변경되는 시점
언마운트(unmount) : 컴포넌트가 더이상 존재하지 않는 시점
render()
컴포넌트가 UI를 렌더링하기 위해 사용
항상 순수해야 하며 부수효과가 없어야 함
같은 입력값(props 또는 state)이 들어가면, 항상 같은 결과물을 반환해야 함
render함수 내부에서 state를 직접 업데이트하는 this.setState를 호출하면 안됨. state를 변경하는 일은 메서드나 다른 생명주기 메서드 내부에서 발생해야 함
componentDidMount()
마운트되고 준비가 된 후 호출되는 생명주기 메서드
render() 와는 다르게 함수 내부에서 this.setState()로 state 값을 변경하는 것이 가능함
this.setState() 호출 시, state가 변경되고, 즉시 렌더링을 시도하는데, 브라우저가 실제로 UI를 업데이트하기 전에 실행되어
사용자가 변경되는 것을 눈치챌 수 없게 만듬
일반적으로 state를 다루는 것은 생성자(constructor)에서 하는 것이 좋다.
생성자 함수에서 할 수 없는것
API 호출 후 업데이트
DOM에 의존적인 작업(이벤트 리스너 추가 등)
componentDidUpdate()
컴포넌트 업데이트가 일어난 이후 즉시 실행됨
일반적으로 state나 props의 변화에 따라 DOM을 업데이트하는 등에 쓰임
this.setState()
를 사용할 수 있음.적절한 조건문으로 감싸지 않는다면
this.setState()
가 계속 호출되는 일이 발생할 수 있음
componentWillUnmount()
컴포넌트가 언마운트 되거나, 사용되지 않기 직전에 호출
메모리 누수나 불필요한 동작을 막기 위한 클린업 함수를 호출하기 위한 최적의 위치
this.setState()
를 호출할 수 없음
shouldComponentUpdate()
state나 prop의 변경으로 리렌더링 되는 것을 막고 싶을 때 사용
컴포넌트의 영향을 받지 않는 변화에 정의할 수 있음
static getDerivedStateFormProps()
render()를 호출하기 직전에 호출
다음에 올 props를 바탕으로 현재 state를 변경하고 싶을 때 사용할 수 있음
static으로 선언되어 this에 접근할 수 없음
반환하는 객체는 내용이 모두 state로 들어가게 되며, null로 반환 시 아무일도 일어나지 않음
getDerivedStateFromProps는 불필요한 사용을 피하는 것이 좋음. 대부분의 경우 상태 동기화는 불필요하거나 다른 방식으로 더 효율적으로 처리될 수 있음. 주로 특별한 경우에만 사용되며, 무분별하게 사용하면 코드 복잡성이 증가할 수 있음.
getSnapShotBeforeUpdate()
DOM이 업데이트되기 직전에 호출
반환되는 값은 componentDidUpdate로 전달됨
DOM에 렌더링되기 전에 윈도우 크기를 조절하거나 스크롤 위치를 조정하는 등의 작업을 처리하는데 용이함
ErrorBoundray
getDerivedStateFormError()
에러 상황에서 실행되는 메서드
반드시 state값을 반환해야 함
render단계
에서 실행렌더링 과정에서 호출되는 메서드이므로, 부수 효과를 발생시키면 안됨
componentDidCatch()
자식 컴포넌트에서 에러가 발생
했을 때 실행getDerivedStateFormError에서 에러를 잡고 state를 결정한 후 실행
commit 단계
에서 실행
주의할 점componentDidCatch는 개발 모드와 프로덕션 모드가 다르게 동작함
개발 모드
에러가 발생하면 window까지 전파
프로덕션 모드
잡히지 않은 에러만 window까지 전파
React.Component vs React.PureComponent
React.Component와 React.PureComponent의 차이는 컴포넌트의 리렌더링 최적화 방식에 있음
React.Component
기본적으로 React.Component는 shouldComponentUpdate 메서드가 구현되지 않은 상태임.
상태(state)나 속성(props)이 변경되면 항상 리렌더링이 발생함.
최적화를 위해 shouldComponentUpdate 메서드를 오버라이드하여 리렌더링을 제어할 수 있음.
React.PureComponent
React.PureComponent는 shouldComponentUpdate 메서드가 내장된 형태로 제공됨.
이 메서드는 **얕은 비교(shallow comparison)**를 통해 props와 state가 변경되지 않았다면 리렌더링을 하지 않음.
객체나 배열과 같은 참조형 데이터가 깊은 구조일 경우 정확히 비교하지 못할 수 있으므로, 객체의 불변성을 유지해야 PureComponent가 효과적임.
React.PureComponent를 사용하면 불필요한 리렌더링을 줄일 수 있지만, 경우에 따라 얕은 비교로 인한 오작동이 발생할 수 있으므로 주의가 필요함.
클래스 컴포넌트의 한계
데이터 흐름을 추적하기 어려움
서로 다른 여러 메서드에서
state의 업데이트
가 일어날 수 있음코드 작성 시, 메서드의 순서가 강제되어 있지 않음에 따라 사람이 읽기가 어려움
생명주기 메서드는 수서가 있지만 작성시 메서드의 순서를 맞춰야 하는 것은 아니기 때문에, 생명주기 메서드와 상관없이 코드가 작성되어 있을 수 있음.
애플리케이션 내부 로직의 재사용이 어려움
컴포넌트 간에 중복되는 로직이 있을 경우
고차 컴포넌트(HOC Component)
로 감싸거나props
를 넘겨줄 경우, 공통로직이 많아질 수록 이를 감싸는 고차 컴포넌트, props가 많아지는wrapper지옥
에 빠질 수 있음.extends
를 이용해 컴포넌트 상속도 가능하지만, 상속되고 있는 클래스의 흐름을 쫓기가 쉽지 않음.
기능이 많아질수록, 컴포넌트의 크기가 커짐
컴포넌트 내에 로직이 많아질수록, 내부에서 처리하는 데이터 흐름이 복잡해져 생명주기 메서드 사용이 잦아지는 경우, 컴포넌트의 크기가 기하급수적으로 커짐
클래스는 함수에 비해 상대적으로 어려움
함수에 비해 클래스의 사용이 비교적 어렵고 일반적이지 않음.
클래스형 컴포넌트를 처음 접하는 사람, 자바스크립트를 조금 해본 사람도 모두 혼란에 빠질 수 있음.
코드 크기의 최적화가 어려움
최종 결과물인 번들 크기를 줄이는게 어려움.
핫 리로딩을 하는데 상대적으로 불리함
클래스형 컴포넌트는 최초 렌더링 시에
instance를 생성하고 내부에서 state를 관리
한다.내부의 render를 수정하면, 반영할 방법은 새로운
instance를 생성
하는 것 뿐이다. 새롭게 생성하며서기존의 instance의 state값이 초기화 된다.
함수형 컴포넌트는
클로저
를 이용하므로,state
가 초기화 되지 않는다. 이 점 떄문에, 핫 리로딩에 불리하다.
핫 리로딩(hot reloading) :코드에 변경 사항이 발생했을 때 앱을 다시 시작하지 않고서도 해당 변경된 코드만 업데이트해 변경 사항을 빠르게 적용하는 기법
Last updated