[RN] React-Native 생명주기 는?

(RN의 한국어 자료가 많아지길 희망하며..)

React Native 라이프 사이클을 궁금했습니다.

기본적으로 프로젝트를 생성하면 시작 파일인App.js 가 있습니다.

여기서Class App이 Component를 상속받는 데, 이 Component를 확인하면 알 수 있을 것 같았습니다.

import React, {Component} from 'react';
... (중략) ...
export default class App extends Component{
render() {
return (
<View style={styles.container}>
<Text style={styles.welcome}>Welcome to React Native!</Text>
<Text style={styles.instructions}>To get started, edit App.js</Text>
<Text style={styles.instructions}>{instructions}</Text>
</View>
);
}
}
... (중략) ...

Component는 reactclass, interface 를 참조합니다.

import React, {Component} from 'react';
...

해당 react 라이브러리의 소스를 확인해보면

즉, Node 프로젝트에서 사용하는 React 모듈의 타입 정보가 담겨있는 d.ts 파일 안을 보면..

~/Users/clintJang/Library/Caches/typescript/3.0/node_modules/@types/react/index.d.ts

아래와 같은 Lifecycle에 관련 된 소스를 확인 할 수 있습니다.

(안보셔도 됩니다.)

... (중략) ...
interface Component<P = {}, S = {}, SS = any> extends ComponentLifecycle<P, S, SS> { }
... (중략) ...
//
// Component Specs and Lifecycle
// ---------------------------------------------------------------
// This should actually be something like `Lifecycle<P, S> | DeprecatedLifecycle<P, S>`,
// as React will _not_ call the deprecated lifecycle methods if any of the new lifecycle
// methods are present.
interface ComponentLifecycle<P, S, SS = any> extends NewLifecycle<P, S, SS>, DeprecatedLifecycle<P, S> {
/**
* Called immediately after a component is mounted. Setting state here will trigger re-rendering.
*/
componentDidMount?(): void;
/**
* Called to determine whether the change in props and state should trigger a re-render.
* `Component` always returns true.
* `PureComponent` implements a shallow comparison on props and state and returns true if any
* props or states have changed.
* If false is returned, `Component#render`, `componentWillUpdate`
* and `componentDidUpdate` will not be called.
*/
shouldComponentUpdate?(nextProps: Readonly<P>, nextState: Readonly<S>, nextContext: any): boolean;
/**
* Called immediately before a component is destroyed. Perform any necessary cleanup in this method, such as
* cancelled network requests, or cleaning up any DOM elements created in `componentDidMount`.
*/
componentWillUnmount?(): void;
/**
* Catches exceptions generated in descendant components. Unhandled exceptions will cause
* the entire component tree to unmount.
*/
componentDidCatch?(error: Error, errorInfo: ErrorInfo): void;
}
... (중략) ...

위 소스는 Component 인터페이스가 ComponentLifecycle를 상속받고 있는 부분과 ComponentLifecycle의 Interface 상세 부분이고, ComponentLifecycle Interface는 NewLifecycle 과 DeprecatedLifecycle의 Interface를 상속받아져 있는 것을 확인 할 수 있습니다.

interface ComponentLifecycle<P, S, SS = any> extends NewLifecycle<P, S, SS>, DeprecatedLifecycle<P, S> { ...

복잡해보이죠?

우선 상세히 보기 전에

간략히 라이프 사이클 관련해서 확인해보면 개인적으로 5가지 정도가 있는 것 같습니다.

그리고 react 16.3 부터는 ..will.. 시점의 메소드는 사용을 지양하려 하는 것을 알 수 있었습니다. (react 17부터는 아예 사용 할 수 없도록 하네요.)

1. 컴포넌스 생성부터 완료의 호출 순서를 보면

constructor ➡️ componetWillMount(depricated) ➡️ render ➡️ componetDidMount

2.prop변화가 있을 경우 호출 순서를 보면

componentWillReceiveProps(depricated) ➡️ shouldComponetUpdate (false 시 업데이트 취소) ➡️ componetWillUpdate(depricated) ➡️ render ➡️ componetDidUpdate

3.state변화가 있으면..

shouldComponetUpdate (false 시 업데이트 취소) ➡️ componetWillUpdate(depricated) ➡️ render ➡️ componetDidUpdate

4.컴포넌트를 제거하면

componentWillUnmount

5. 구성요소에 문제가 있을 경우

componentDidCatch


그리고 위 메소드 들이 정의된 ComponentLifecycle, NewLifecycle, DeprecatedLifecycle 의 정보를 바탕으로 아래에 상세히 정리해 보았습니다.

ComponentLifecycle

componentDidMount?(): void;
  • 컴퍼넌트가 마운트 된 직후에 불려지게 됩니다.
  • 여기에 상태를 설정하면 다시 렌더링이 시작됩니다.
shouldComponentUpdate?(nextProps: Readonly<P>, nextState: Readonly<S>, nextContext: any): boolean;
  • props 와states의 변경이 재 렌더링을 트리거 해야하는지 여부를 결정하기 위해 호출됩니다.
  • props 또는 states 가 바뀌었을 때 호출 됩니다.
  • false가 반환되면, render, componentWillUpdate, componentDidUpdate는 호출되지 않습니다.
componentWillUnmount?(): void;
  • 컴퍼넌트가 제거(파기)되기 직전에 불려지게 됩니다.
  • componentDidMount에서 생성 된 DOM 요소 정리와 같이.. 이 메소드에서 는 필요한 것을 정리하는 역활을 처리하면 됩니다.
componentDidCatch?(error: Error, errorInfo: ErrorInfo): void;
  • 하위 구성 요소에서 생성 된 예외가 있을 경우 호출 됩니다.
  • 처리되지 않은 예외로 인해 전체 구성 요소 트리가 마운트 해제됩니다.

NewLifecycle

getSnapshotBeforeUpdate?(prevProps: Readonly<P>, prevState: Readonly<S>): SS | null;
  • render의 결과를 적용하기 전에 실행됩니다.
  • componentDidUpdate에 제공 할 객체를 반환합니다.
  • render가 변경되기 전에 스크롤 위치와 같은 것을 저장하는데 유용합니다.
  • 참고 : getSnapshotBeforeUpdate가 있으면 더 이상 사용되지 않는 라이프 사이클 이벤트가 실행되지 않습니다.
componentDidUpdate?(prevProps: Readonly<P>, prevState: Readonly<S>, snapshot?: SS): void;
  • 업데이트가 발생한 직후에 호출됩니다. 단, 초기 렌더링에는 호출되지 않습니다.
  • 파라미터중에 snapshot은 getSnapshotBeforeUpdate가있는 경우에만 존재하며 null이 아닌 것을 반환합니다.

DeprecatedLifecycle

아직 사용할 수 있지만, 앞으로 사용되지 않을 라이프사이클 메소드 입니다.

lifecycle에서 will에 해당하는 메소드는 앞으로 지양하려하는 것을 알 수 있습니다. 여기의 메소드는 이제 사용을 자제하거나 안하는 것이 좋을 것 같습니다.

componentWillMount?(): void;
  • react 16.3 에 deprecated 되었고, react 17부터는 사용할 수 없습니다.
  • render가 시작 되기전에 호출 되며, 마운트 되기 전에 호출 됩니다.
  • 이 방법으로 side-effects 또는 subscriptions를 피하세요.
  • 참고 : getSnapshotBeforeUpdate 또는 getDerivedStateFromProps가 있으면 호출되지 않습니다.
UNSAFE_componentWillMount?(): void;
  • react 16.3 에 deprecated 되었고, 대신에 componentDidMount 나 constructor에서 사용하길 권장합니다, react 17부터는 사용할 수 없습니다.
  • render가 시작 되기전에 호출 되며, 마운트 되기 전에 호출 됩니다.
  • 이 방법으로 side-effects 또는 subscriptions를 피하세요.
  • 참고 : getSnapshotBeforeUpdate 또는 getDerivedStateFromProps가 있으면 호출되지 않습니다.
componentWillReceiveProps?(nextProps: Readonly<P>, nextContext: any): void;
  • react 16.3에 deprecated되었고, 대신에 static getDerivedStateFromProps을 사용하길 권장한다고 합니다.react 17부터는 사용할 수 없습니다.
  • setState가 호출되면 실행되지 않습니다.
  • 새로운 props를 받을 때 호출 됩니다.
  • 새 props와 기존의 props를 비교할 수 있습니다.
  • 참고 : getSnapshotBeforeUpdate 또는 getDerivedStateFromProps가 있으면 호출되지 않습니다.
UNSAFE_componentWillReceiveProps?(nextProps: Readonly<P>, nextContext: any): void;
  • react 16.3에 deprecated되었고, 대신에 static getDerivedStateFromProps을 사용하길 권장한다고 합니다.
  • setState가 호출되면 실행되지 않습니다.
  • 새로운 props를 받을 때 호출 됩니다.
  • 새 props와 기존의 props를 비교할 수 있습니다.
  • 참고 : getSnapshotBeforeUpdate 또는 getDerivedStateFromProps가 있으면 호출되지 않습니다.
componentWillUpdate?(nextProps: Readonly<P>, nextState: Readonly<S>, nextContext: any): void;
  • react 16.3에 deprecated되었고, 대신에 getSnapshotBeforeUpdate을 사용하시길 권장한다고 합니다. react 17부터는 사용할 수 없습니다.
  • 새로운 Props 또는 state가 수신하여 렌더링 직전에 호출됩니다. 초기 렌더링에는 호출되지 않습니다.
  • 주의! 여기에서 setState 를 하시면 안됩니다.
  • 참고 : getSnapshotBeforeUpdate 또는 getDerivedStateFromProps가 있으면 호출되지 않습니다.
UNSAFE_componentWillUpdate?(nextProps: Readonly<P>, nextState: Readonly<S>, nextContext: any): void;
  • react 16.3에 deprecated되었고, 대신에 getSnapshotBeforeUpdate을 사용하시길 권장한다고 합니다.
  • 새로운 Props 또는 state가 수신하여 렌더링 직전에 호출됩니다. 초기 렌더링에는 호출되지 않습니다.
  • 주의! 여기에서 setState 를 하시면 안됩니다.
  • 참고 : getSnapshotBeforeUpdate 또는 getDerivedStateFromProps가 있으면 호출되지 않습니다.

그리고 위 라이프 사이클에는 없지만,

constructor
  • 생성자 메소드입니다. 컴포넌트가 처음 만들어질 때 실행됩니다.
render
  • 컴포넌트를 만드는 방법을 제시하고 만들기 시작합니다.

현재 작성한 개발 환경 정보는

프로젝트의 최상위 폴더에서 info 쉘 커맨드를 이용하면 쉽게 확인 하실 수 있습니다.

  • 아래는 제 개발 환경입니다.
  • react : 16.4.1. 과 react-native : 0.56.0 을 확인할 수 있습니다.
$ react-native info
Scanning folders for symlinks in /Users/clintjang/Documents/중략/node_modules (26ms)
React Native Environment Info:
System:
OS: macOS High Sierra 10.13.6
CPU: x64 Intel(R) Core(TM) i7-3740QM CPU @ 2.70GHz
Memory: 33.43 MB / 16.00 GB
Shell: 3.2.57 - /bin/bash
Binaries:
Node: 10.8.0 - /usr/local/bin/node
Yarn: 1.9.4 - /usr/local/bin/yarn
npm: 6.2.0 - /usr/local/bin/npm
Watchman: 4.9.0 - /usr/local/bin/watchman
SDKs:
iOS SDK:
Platforms: iOS 11.4, macOS 10.13, tvOS 11.4, watchOS 4.3
Android SDK:
Build Tools: 23.0.2, 25.0.0, 25.0.1, 26.0.2, 27.0.1, 27.0.3, 28.0.1
API Levels: 21, 22, 23, 24, 25, 26, 27, 28
IDEs:
Android Studio: 3.1 AI-173.4907809
Xcode: 9.4.1/9F2000 - /usr/bin/xcodebuild
npmPackages:
react: 16.4.1 => 16.4.1
react-native: 0.56.0 => 0.56.0
npmGlobalPackages:
create-react-native-app: 1.0.0
react-native-cli: 2.0.1

공부하면서 틀린 부분이 확인되면 바로바로 수정해 두겠습니다.~

읽어주셔서 감사합니다.

즐거운 하루 되세요 :) 🙇‍