리액트 클래스형 컴포넌트 라이프 사이클 정리

리액트 클래스형 컴포넌트 라이프 사이클 정리

시작

class component 생성하는 방법

React.Component를 확장하는 ES6 class를 생성. render()라고 불리는 빈 메서드 추가 render() 메서드 내에서는 props를 this.props로 받음.

class에 local state 추가

초기 this.state를 지정하는 class constructor를 추가합니다 constructor 메서드는 class로 생성된 객체를 생성하고 초기화하기 위한 특수한 메서드이고 클래스에 한개만 존재할 수 있습니다.

constructor 는 부모 클래스의 constructor를 호출하기 위해 super 키워드를 사용할 수 있습니다.

는 부모 클래스의 constructor를 호출하기 위해 super 키워드를 사용할 수 있습니다. super 는 부모 클래스 생성자를 가리킵니다. 리액트 에서는 React.Component를 가리키고 있습니다.

는 부모 클래스 생성자를 가리킵니다. 리액트 에서는 React.Component를 가리키고 있습니다. Class Component는 항상 props로 기본 constructor를 호출해야 합니다.추가적으로 바벨의 plugin-transform-class-properties를 사용해서. constructor의 생략이 가능하다.

[추가예정] class Test extends React.Component{ constructor(props) { super(props); this.state = {name: 'jiwon'} } render() { return ( {this.state.name} ) } }

생명주기 메서드

import React from 'react'; import ReactDOM from 'react-dom'; import reportWebVitals from './reportWebVitals'; class Test extends React.Component{ constructor(props) { super(props); this.state = { name: 'jiwon', date: new Date() } } componentDidMount() { this.timerID = setInterval(() => this.tick(), 1000); // 기준간격을 두고 주기적으로 이벤트 발생 } componentWillUnmount() { clearInterval(this.timerID); //기준 간격이 지정된 반복 작업을 중단함. } tick() { this.setState({ date : new Date() }) } render() { return ( {this.state.name} {this.state.date.toLocaleTimeString()} ) } } ReactDOM.render( , document.getElementById('root') );

메서드의 호출 순서 요약

가 ReactDOM.render()로 전달되었을 때 React는 Test Component 의 constructor 호출. 그리고 this.state 초기화. React는 Test 컴포넌트의 render() 메서드 호출(이를 통해 출력값을 인지함) 후 Test 의 렌더링 출력값을 일치시키기 위해 DOM update. Test 출력값이 DOM에 삽입되면 React가 ComponentDidMount() 메서드 호출 -> 내부 코드 수행 매초 브라우저가 tick() 메서드 호출. tick()에서 Test Component 는 setState에 date : new Date() 를 호출하면서 UI업데이트를 진행합니다. setState를 통해 React는 state가 변경된 것을 인지하고 화면에 표시될 내용을 알아내기위해 render() 메서드를 다시 호출합니다. 이 때 render() 메서드 안의 this.state.date가 달라지고 렌더링 출력 값은 업데이트 된 시각을 포함합니다. Test Component가 DOM으로부터 한 번이라도 삭제된 적이 있으면 React는 ComponentWillUnmount() 생명주기 메서드를 호출합니다.

심화학습

컴포넌트 생명주기(LifeCycle)

Mount

컴포넌트의 인스턴스가 생성되어 DOM 상에 삽입될 때에 순서대로 호출

1. constructor()

리액트 컴포넌트의 생성자(constructor())은 컴포넌트가 마운트되기 전에 호출됩니다.

React.Component를 상속한 컴포넌트의 생성자를 구현할 때는 다른 구문에 앞서 super(props)를 호출해야합니다.

constructor() 내부에서는 setState를 사용하는 것이 아니라 this.state에 초기 값을 할당합니다. (생성자는 this.state를 직접할당할 수 있는 유일한 곳)

⚠️ 생성자 내에서는 side effect를 발생시키거나 subscription을 수행하면 안됩니다. 해당 경우엔 componentDidMount()를 대신 사용해야합니다.

⚠️ state에 props를 복사하면 안됩니다. props의 값이 바뀌어도 state에 반영되지 않습니다. 따라서 props의 갱신을 의도적으로 무시할 때 이런 패턴을 사용할 수 있습니다.

1-1. super 안 쓰면 어떻게 되나?

[클래스 공부하고 나서 작성]

class Test extends React.Component{ constructor(props) { this.state = { name: 'jiwon', date: new Date() } } ...

ReferenceError: Must call super constructor in derived class before accessing 'this' or returning from derived constructor

super를 사용하지 않고 this를 사용하자 에러가 났습니다.

1-2. super 왜 써야하나?

자바스크립트는 상속 클래스의 생성자 함수(constructor())와 그렇지 않은 생성자 함수를 구분합니다. 상속 클래스의 생성자 함수(constructor())에는 특수 내부 프로퍼티인 [[ConstructorKind]]:"derived" 가 이름표처럼 붙습니다.

(상속 클래스가 아니면 "base" 값을 가짐)

일반 클래스의 생성자 함수와 상속 클래스 생성자 함수간의 차이

일반 클래스가 new 와 함께 실행되면 빈 객체가 만들어지고 this에 이 객체를 할당.

와 함께 실행되면 빈 객체가 만들어지고 this에 이 객체를 할당. 상속 클래스 생성자 함수는, 빈 객체를 만들고 this에 이 객체를 할당하는 일을 부모 클래스 생성자가 해주길 기대.

이런 차이 때문에 상속 클래스 생성자 함수는 super를 호출해서 부모 생성자를 실행해줘야합니다. 안 그러면 this가 될 객체는 만들어지지 않습니다.

1-3. 그럼 super에 props를 전달하지 않으면?

class Test extends React.Component{ constructor(props) { super(); this.state = { name: 'jiwon', date: new Date() } }

props인자 없이 super()를 호출했는데 render나 다른 메서드에서도 this.props에 접근이 가능합니다.

이는 리액트가 생성자를 호출한 직후에 인스턴스에 props를 할당하는 것이기 때문입니다. 하지만 생성자가 끝나기 전에 this.props는 undefined가 될 것이기 때문에 super를 사용하는 것이 좋습니다.

[질문] this.props = props 와 super(props)의 차이

static getDerivedStateFromProps()

getDerivedStateFromProps 는 최초 마운트 시와 갱신 시 모두에서 render 메서드를 호출하기 직전에 호출됩니다. (state 갱신을 위한 객체나, null을 반환)

이 메서드는 시간이 흐르는 것에 따라 변하는 props에 state가 의존하는 드문 사례를 위해 존재합니다.

render()

render() 메서드는 클래스 컴포넌트에서 반드시 구현돼야하는 유일한 메서드이고, 이 메서드가 호출되면 this.props와 this.state의 값을 활용하여 React 엘리먼트 , 배열 과 Fragment , Portal , 문자열과 숫자 , Boolean 또는 null 을 반환해야합니다.

render() 는 순수해야합니다. 컴포넌트의 state를 변경하지 않고 호출 마다 동일한 결과를 반환하고 브라우저와 직접적으로 상호작용하지 않습니다.

[질문] render()가 왜 순수함수인지? 렌더 내에있는 ref등으로 직접 접근하는 것은?

React DOM 및 refs 업데이트

componentDidMount()

componentDidMount() 는 컴포넌트가 마운트된 직후, 즉 트리에 삽입된 직후에 호출됩니다. DOM 노드가 있어야하는 초기화 작업은 이 메서드에서 이뤄지면 됩니다. (네트워크 요청에 적절한 위치입니다.)

Update

컴포넌트가 re-rendering 될 때, 순서대로 호출되는 methods

static getDerivedStateFromProps()

shouldComponentUpdate()

shouldComponentUpdate(nextProps, nextState)

props 나 state 가 변경 되었을 때 리렌더링 여부를 return 값으로 반환합니다.

shouldComponentUpdate 를 사용하면 state 또는 props의 변화가 컴포넌트의 출력 결과에 영향을 미치는지 여부를 React가 알 수 있습니다. 기본 동작은 매 state마다 다시 렌더링을 수행하고, 대부분 경우 기본 동작을 따라야합니다.

이 메서드는 초기 렌더링 또는 forceUpdate()가 사용될 때는 호출되지 않습니다.

직접 작성 보다 PureComponent를 사용하는 것이 좋고 직접 작성할 때는 this.props와 nextProps, 그리고 this.state와 nextState를 비교한뒤 true, false를 반환할 수 있습니다.

false를 반환할 경우 render(), 그리고 componentDidUpdate()는 호출되지 않습니다.

class Test extends React.Component{ constructor(props) { super(props); this.state = { name: 'jiwon', } } componentDidUpdate() { console.log("updated") } render() { return ( {this.state.name} this.setState({name:'jiwon'})}>업데이트 ) } }

위의 코드는 업데이트를 누르면 리렌더링 되며 console.log가 찍힙니다.

여기에서 shouldComponentUpdate를 사용해보면

false가 반환되어 updated 는 로그에 찍히지 않는 것을 확인할 수 있습니다.

render

getSnapshotBeforeUpdate

getSnapshotBeforeUpdate(prevProps, prevState)

렌더링 결과가 실제 DOM에 반영되엇을 때 호출됩니다. 그리고 다음순서 메서드인 componentDidUpdate는 컴포넌트가 업데이트된 후에 호출됩니다. 이름처럼 업데이트 되기전 snapshot(props & states)를 확보하는게 목적이며, 컴포넌트가 DOM으로 부터 스크롤 위치등과 같은정보를 이후 변경되기 전에 얻을 수 있고, 이 메서드가 반환하는 값은 componentDidUpdate의 인자로 전달됩니다.

따라서 snapshot을 이 메서드에서 리턴하면 이후에 componentDidUpdate에서는 이전 속성, 이전 상태, snapsot을 이용해 돔의 상태값 변화를 알 수 있습니다.

[일단 보류] 왜 반영되었을 때?????

componentDidUpdate()

componentDidUpdate(prevProps, prevState, snapshot)

componentDidUpdate 는 업데이트가 일어난 직후에 호출됩니다. 최초 렌더링에는 호출되지 않습니다.

여기에서는 setState()를 호출할 수 있지만 조건문이 없다면 무한반복이 일어날 수 있습니다.

Unmount

컴포넌트가 DOM 상에서 제거될 때에 호출되는 method

componentWillUnmount()

componentWillUnmount()

componentWillUnmount()는 마운트가 해제되어 제거되기 직전에 호출됩니다. 이 컴포넌트는 다시 렌더링 되지 않으므로 setState()를 호출해서는 안됩니다.

참고 및 출처

from http://pannchat.tistory.com/136 by ccl(A) rewrite - 2021-11-26 18:00:51