5.4 생명주기 메서드

생명주기 메서드는 리액트의 클래스 컴포넌트에서만 사용이 가능합니다.

함수 컴포넌트에서는 useEffect()라는 리액트 훅을 이용하여 유사한 기능을 구현할 수 있습니다.

생명주기 메서드는 다음 세 가지의 경우에서 자동으로 호출되는 메서드를 말합니다.

  • 컴포넌트가 마운트 될 때
    • 리액트 컴포넌트가 애플리케이션의 컴포넌트 트리에 추가되어 브라우저 화면에 나타날 때의 단계별 생명주기 메서드
  • 컴포넌트가 업데이트 될 때
    • 리액트 컴포넌트의 상태, 속성이 변경되어 브라우저 화면이 갱신될 때의 단계별 생명주기 메서드
  • 컴포넌트가 언마운트 될 때
    • 리액트 컴포넌트가 애플리케이션의 컴포넌트 트리에서 제거되어 브라우저 화면에 사라질 때의 생명주기 메서드

5.4.1 컴포넌트가 마운트될 떄

  • constructor
    • 컴포넌트가 생성될 때 호출되는 생명주기 메서드입니다.

    • 생성자에서는 반드시 super(props)를 호출해야 하며, 이를 호출하지 않으면 컴포넌트에서 props를 사용할 수 없습니다.

    • 생성자는 this.state에 객체를 할당하여 컴포넌트의 상태를 초기화하기 위해 작성합니다.

    • 생성자 내부에서는 초기화만 가능하며 this.setState() 메서드를 이용하여 상태를 변경하면 안됩니다.

    • 만약 상태를 초기화할 일이 없다면 생성자를 작성하지 않아도 됩니다.

      constructor(props) {
      	this.state = {name: "홍길동", age: 20}
      }
    • 타입스크립트 언어에서는 constructor를 사용하면 this.state 속성의 타입을 지정할 수 없습니다.

      • 따라서 constructor를 사용하더라도 any 타입을 사용해야 하므로 권장하지 않습니다.

      • 대신 클래스 내의 state 인스턴스 멤버를 지정하는 방법을 사용합니다.

        type StateType = {
        	name: string;
        	age: number;
        }
        
        export default class Test extends Component<{}, StateType> {
        	state : StateType = {naem: "홍길동", age: 20}
        	
        	render() {
        		const {name, age} = this.state
        		return <div> {name}님의 나이 : {age} </div>
        	}
        }
  • getDerivedStateFromProps 정적 메서드
    • 컴포넌트의 상태가 부모 컴포넌트로부터 전달받은 속성에 의해 달라지는 경우에 사용합니다.
    • 정적 메서드이므로 반드시 static 키워드를 지정해주어야 합니다.
      • 이는 props와 state에 해당하는 두 개의 인자를 전달받습니다.

      • props는 전달받은 속성 객체이며 state는 컴포넌트의 기존 상태입니다.

      • props를 이용하여 새로운 상태를 만들고 이를 리턴합니다.

        type Props = { level: string }
        type State = { discountRate: number ; customerName: string }
        
        export default class Child extends Component<Props, State> {
        	state: State = { discountRate:0, customerName: "홍길동"};
        	
        	static getDerivedStateFromProps(props: Props, state: State){
        		let tempRate = 0
        		if (props.level === "GOLD") tempRate = 0.15
        		else if (props.level === "SILVER") tempRate = 0.1 
        		else if (props.level === "BRONZE") tempRate = 0.05
        		else tempRate = 0.02
        		return {...state, discountRate: tempRate}
        	}
        	
        	render() {
        		return(
        			<div>
        				{this.state.customerName} 님의 할인율은 {this.state.discountRate * 100}% 입니다.
        			</div>
        		)
        	}
        }
  • render 메서드
    • 컴포넌트를 가상 DOM으로 렌더링하는 메서드입니다.
    • 상태와 속성을 이용하여 리액트 엘리먼트 등으로 렌더링합니다.
    • 해당 메서드는 상태와 속성이 변경되지 않는다면 같은 결과를 리턴합니다.
  • componentDidMount 메서드
    • 컴포넌트의 마운트가 완료되고 나서 브라우저 DOM의 트리에 반영이 된 후 호출되는 메서드입니ㅏㄷ.
    • 브라우저 DOM이 완성된 후에 실행해야하는 초기화 작업을 하기에 적합합니다.
    • API를 호출하여 결과를 받아서 this.setState() 메서드로 상태를 변경하고 DOM에 출력해야하는 경우에는 이를 사용합니다.

5.4.2 컴포넌트가 업데이트 될 때

  • getDerivedStateFromProps 정적 메서드
    • 컴포넌트 마운트 시와 하는 역할이 같습니다.
  • shouldComponentUpdate 메서드
    • 렌더링 성능을 최적화할 때 자주 사용됩니다.

    • 해당 메서드에 전달되는 인자는 새롭게 전달된 nextProps, nextState 입니다.

    • 리턴값은 boolean 형식입니다.

      • 리턴값이 true이면 다음 단계의 생명주기 메서드(render)가 호출됩니다.
      • false이면 다음 단계의 생명주기로 넘어가지 않습니다.
    • 해당 메서드에서는 새롭게 전달된 속성과 상태를 기존의 속성인 this.props와 상태인 this.state와 비교하여 다시 렌더링할지를 결정합니다.

      shouldComponentUpdate(nextProps: props, nextState: State) : boolean {
      
      }
    • 깊은 비교를 수행하는 경우에는 많은 시스템 리소스가 사용되므로 렌더링 성능의 최적화가 어렵습니다.

      • 이를 위해 immer 혹은 전개 연사자를 이용하여 불변성을 가지는 변경 작업을 수행해야 합니다.
  • getSnapshotBeforeUpdate 메서드
    • render() 메서드가 호출되어 가상 DOM으로의 쓰기 작업이 완료된 후, 브라우저 DOM에 업데이트가 되기 전에 실행됩니다.

    • 변경 전의 DOM 상태 정보를 획득하여 스냅샷 값으로 리턴하여 componentDidUpdate() 메서드의 세 번째 인자로 받아낼 때 사용합니다.

      getSnapshotBeforeUpdate(prevProps, prevState) {
      	return 
      }
  • componentDidUpdate 메서드
    • 브라우저 DOM까지 업데이트가 완료된 이후에 해당 메서드가 실행됩니다.

    • 해당 메서드는 컴포넌트가 업데이트되고 DOM을 변경하고자 할 때 사용합니다.

    • 현재의 속성과 상태인 this.props, this.state를 이전의 속성, 상태와 비교하여 차이가 있다면 외부 API를 요청하는 등의 작업을 수행하도록 활용할 수 있습니다.

      componentDidUpdate(prevProps, prevState, snapshot){
      
      }

5.4.3 컴포넌트가 언마운트 될 때

  • componentWillUnmount 메서드
    • 컴포넌트가 애플리케이션의 컴포넌트 트리에서 삭제되기 직전에 실행됩니다.
    • 이는 componentDidMount 생명주기 메서드와 짝을 이루어 사용됩니다.
    • 외부 리소스에 연결한 경우에는 반드시 해당 메서드를 이용하여 연결을 해제해야 합니다.

5.5 가상 DOM 과 조정

5.5.2 가상 DOM과 브라우저 DOM

가상 DOM을 사용하는 이유는 브라우저 DOM을 조작하는 것이 느리기 때문입니다.

이 중에서 화면에 그려내는 작업이 느립니다.

브라우저의 화면은 reflow와 repaint 두 단계를 거쳐서 렌더링됩니다.

  • reflow : 렌더링할 DOM 트리를 새롭게 만들고 HTML 요소들의 위치와 크기를 계산해 배치하는 단계
    • reflow 완료 후 HTML 요소에 스타일을 입히고 UI를 그려내는 repaint 단계가 실행됩니다.
  • 가상 DOM은 이러한 reflow repaint 작업을 작업을 줄여줍니다.
    • 이전 버전의 DOM 트리와 현재 버전의 DOM 트리를 비교함으로써 차이가 나는 부분만을 브라우저 DOM에 업데이트 합니다.
    • 이를 reconciliation이라고 합니다.

5.5.2 key 특성

key 특성은 컴포넌트 내부에서 반복적으로 자식 컴포넌트와 요소를 렌더링할 때 지정합니다.

일부 항목들이 추가 삭제 변경되는 경우에 변경 사항을 추적하는 것은 쉽지 않기 때문에 이를 추적하기 위해 key 특성을 사용합니다.

key를 지정하지 않으면 배열 데이터의 어떤 값이 어느 요소에 렌더링됐는지를 추적할 방법이 없습니다.

  • 따라서 이와 같은 경우, 리스트 전체를 다시 렌더링 해야 합니다.

5.5.3 생명주기 메서드를 이용한 렌더링 최적화

shouldComponentUpdate 생명주기 메서드는 컴포넌트의 render 메서드가 호출되기 전에 실행됩니다.

렌더링 여부를 빠르게 결정하기 위해서는 불변성을 가진 상태 변경이 필요합니다.

리액트이 렌더링 최적화를 위해 가장 기본적으로 필요한 요구 사항은 불변성을 가지도록 상태를 변경하는 것입니다.

profile
let David_Oh === UX+Programming

0개의 댓글