클래스 컴포넌트
import React from 'react'
// props 타입 선언
interface Props {
required?: boolean
text: string
}
// state 타입 선언
interface State {
count: number
isLimited?: boolean
}
class Component extends React.Component<Props, State> {
private constructor(props : Props) {
super(props)
this.state = {
count: 0,
isLimited: false,
}
}
render() {
const {
props: {required, text},
state: {count, isLimited},
}=this
return (
<div>{required ? '필수' : '필수아님'}</div>
<div>{text}</div>
)
}
}
- 클래스 컴포넌트를 만들기 위해 클래스를 선언하고 extends로 만들고 싶은 컴포넌트(React.Component / React.PureComponent)를 상속받아야 함
- constructor()
- 컴포넌트가 초기화되는 시점에 호출됨
- 컴포넌트의 state를 초기화할 수 있음
- super()을 통해 상위 컴포넌트에 접근할 수 있게됨
- props
- 컴포넌트에 특정 속성을 전달하는 용도로 사용
- state
- 클래스 내부에서 관리하는 값
- 항상 객체임
- state에 변화가 있을 때마가 리렌더링이 발생
- 메서드
- 렌더링 함수 내부에서 사용되는 함수
- 보통 DOM 에서 발생하는 이벤트와 함께 사용함
- constructor에서 this 바인드를 하는 방법
- 화살표 함수를 쓰는 방법
클래스 컴포넌트의 생명주기 메서드
- 생명주기 메서드가 실행되는 시점
- 마운트 : 컴포넌트가 마운팅(생성)되는 시점
- 업데이트 : 이미 생성된 컴포넌트의 내용이 변경(업데이트)되는 시점
- 언마운트 : 컴포넌트가 더 이상 존재하지 않는 시점
- 생명주기 메서드
- render()
- 리액트 클래스 컴포넌트의 유일한 필수 값
- 컴포넌트가 UI를 렌더링하기 위해 사용함
- 마운트와 업데이트 과정에서 일어남
- 항상 순수해야 하며 부수 효과가 없어야 함
- state를 직접 업데이트하는 this.setState를 호출해서는 안됨
- componentDidMount()
- 클래스 컴포넌트가 마운트되고 준비되는 즉시 실행됨
- state 값 변경 가능함
- this.setState를 호출했다면 state가 변경되어 즉시 다시 한번 렌더링을 시도하는데, 브라우저가 실제로 UI를 업데이트하기 전에 실행되어 사용자가 변경되는 것을 눈치핼 수 없게 만듬
- 하지만 성능 문제를 일으킬 수 없기 때문에 state를 다루는 것은 생성자에서 하는 것이 좋음
- 생성자 함수에서 할 수 없거나 API 호출 후 업데이트, DOM에 의존작인 작업등을 하기 위해서만 state 변경이 허용됨
- componentDidUpdate()
- 컴포넌트 업데이트가 일어난 이후 바로 실행됨
- state나 props의 변화에 따라 DOM을 업데이트하는 등에 쓰임
- this.setState를 사용할 수 있지만 적절한 조건문으로 감싸지 않는다면 무한 호출이 발생할 수 있음
- componentWillUnmount()
- 컴포넌트가 언마운트되거나 더 이상 사용되지 않기 직전에 호출됨
- 메모리 누수나 불필요한 작동을 막기 위한 클린업 함수를 호출하기 위한 최적의 함수
- this.setState를 호출할 수 없음
- 이벤트를 지우거나, API 호출을 취소하거나, setTimeout, setInterval으로 생성된 타이머를 지우는 등의 작업에 유용함
- shouldComponentUpdate()
- state나 props의 변경으로 리액트 컴포넌트가 다시 리렌더링되는 것을 막고 싶을 때 사용
- 하지만, 일반적으로 state의 변화에 따라 컴포넌트가 리렌더링되는 것은 굉장히 자연스러운 일이므로 이 메서드는 특정한 성능 최적화 상황에서만 고려해야 함
- static getDerivedStateFromProps()
- componentWillReceiveProps()를 대체할 수 있는 메서드
- render()를 호출하기 직전에 호출됨
- static으로 선언돼 있어 this에 접근할 수 없음
- 반환하는 객체는 null이 아니면 해당 객체의 내용이 모두 state에 들어가게 됨
- getSnapShotBeforeUpdate()
- componentWillUpdate()를 대체할 수 있는 메서드
- DOM이 업데이트되기 직전에 호출됨
- 반환되는 값은 componentDidUpdate로 전달됨
- DOM에 렌더링되기 전에 윈도우 크기를 조절하거나 스크롤 위치를 조정하는 등의 작업을 처리하는 데 유용함
- static getDerivedStateFromError()
- 자식 컴포넌트에서 에러가 발생했을 때 호출되는 에러 메서드
- error를 인수로 받음
- 반드시 state값을 반환해야 함
- 부수 효과를 수행할 수 없음 <= render 단계에서 실행되기 때문
- componentDidCatch()
- 자식 컴포넌트에서 에러가 발생했을 때 getDerivedStateFromError에서 에러를 잡고 state를 결정한 이후에 실행됨
- 두 개의 인수를 받음
- error
- 어떤 컴포넌트가 에러를 발생시켰는지 정보를 가지고 있는 info
- 부수 효과를 수행할 수 있음 <= 커밋 단계에서 실행되기 때문
- ErrorBoundary를 만들기 위한 목적으로 많이 사용
- render()
클래스 컴포넌트의 유형
- Component
- state가 업데이트되는 대로 렌더링이 발생
- PureComponent
- state 값에 대해 얕은 비교를 수행해 결과가 다를 때만 렌더링을 수행함
- 객체와 같이 복잡한 구조의 데이터 변경 감지 못함
클래스 컴포넌트의 한계
- 데이터 흐름 추적 어려움 : 서로 다른 여러 메서드에서 state의 업데이트가 일어날 수 있으며, 메서드의 순서가 강제되어 있지 않아 사람이 읽기 어려움
- 애플리케이션 내부 로직의 재사용 어려움 : wrapper hell 발생 가능성 문제가 있음
- 기능이 많아질수록 컴포넌트의 크기가 커짐 : 생명주기 메서드 사용이 잦아지는 경우 컴포넌트의 크기가 기하급수적으로 커짐
- 함수에 비해 상대적으로 어려움 : 함수에 비해 클래스의 사용이 어렵고 일반적이지 않음
- 코드 최적화 어려움
- 핫 리로딩을 하는데 상대적으로 불리함 : 핫 리로딩이란 코드에 변경 사항이 발생했을 때 앱을 다시 시작하지 않고서도 해당 변경된 코드만 업데이트해 변경 사항을 빠르게 적용하는 기법, 클래스 컴포넌트는 최초 렌더링 시 인스턴스를 생성하고 그 내부에서 state값을 관리하는데 변경 사항을 반영하기 위해서는 새롭게 instance를 생성하는 방법밖에 없음
함수 컴포넌트
import { useState } from 'react'
type Props = {
required?: boolean
text: string
}
export function Component({required, text} : Props) {
const [count, setCount] = useState(0);
const [isLimited, setIsLimited] = useState(false);
return (
<div>{required ? '필수' : '필수아님'}</div>
...
)
}
- render 내부에서 필요한 함수를 선언할 때 this 바인딩을 조심할 필요 없음
- state는 객체가 아닌 각각의 원시값으로 관리되어 훨씬 사용하기 편함
- 렌더링하는 코드인 return문에서도 굳이 this를 사용하지 않더라고 props와 state에 접근할 수 있음
함수 컴포넌트 vs 클래스 컴포넌트
클래스 컴포넌트 | 함수 컴포넌트 | |
생명주기 메서드 | O render 메서드가 있는 React.Component를 상속받아 구현하는 자바스크립트 클래스이기 때문. 생명주기 메서드는 React.Component로 부터 상속받는 것 |
X props를 받아 단순히 리액트요소만 반환하는 함수 useEffect로 생명주기 메서드를 비슷하게 구현 가능함 |
렌더링된 값 | 렌더링된 값을 고정하지 못함 props의 값을 항상 this로부터 가져오는데 props는 외부에서 변경되지 않는 이상 불변 값이지만 this가 가리키는 객체인 컴포넌트의 인스턴스의 멤버는 변경 가능한 값이기 때문임 즉, 생명주기 메서드가 변경된 값을 읽을 수 있음 |
렌더링된 값을 고정함 |
렌더링 시점 | 시간의 흐름에 따라 변화하는 this를 기준으로 렌더링이 일어남 | 렌더링이 일어날 때마다 그 순간의 값인 props와 state를 기준으로 렌더링됨 |
'FE > 리뷰' 카테고리의 다른 글
[모던 리액트 딥다이브] 2.5장 메모이제이션 (0) | 2024.07.13 |
---|---|
[모던 리액트 딥다이브] 2.4장 렌더링 (0) | 2024.07.13 |
[모던 리액트 딥다이브] 2.2장 가상 DOM과 리액트 파이버 (0) | 2024.07.07 |
[모던 리액트 딥다이브] 2.1장 JSX (0) | 2024.07.07 |
[모던 리액트 딥다이브] 1.7장 타입스크립트 (0) | 2024.06.29 |