react의 각각의 컴포넌트는생성 -> 업데이트 -> 제거
단게를 차례로 겪는 생명주기(Life Cycle)을 가지고 있다.
크게 3가지로 나눌 수 있다.
생성(mount), 업데이트(update), 제거(unmount)
이다.
마운트
는 컴포넌트 함수가 실행되고 결과물로 나온 Element들이 virtualDOM에 삽입되고 실제DOM을 업데이트하기까지의 과정이다.
언마운트
는 DOM에서 제거되는 것이다.
constructor -> render -> componeneDidMount
react 컴포넌트의 생성자는 해당 컴포넌트가 마운트되기 전에 호출한다.
1. this.state로 state 값을 선언/초기화
2. 이벤트 처리 메서드를 바인딩
constructor(props) {
super(props);
// 여기서 this.setState()를 호출하면 안 된다!
this.state = { counter: 0 };
this.handleClick = this.handleClick.bind(this);
}
주의할 점
1. 메서드를 바인딩하거나 state
를 초기화하는 작업이 없다면, 해당 React 컴포넌트에는 생성자를 구현하지 않아도 된다.
2. super(props)
를 호출하지 않으면 this.props
가 생성자 내에서 정의되지 않아 버그로 이어질 수 있다.
3. constructor 내부에서 setState
등의 업데이트를 실행하지 말자. 필요하다면 state에서 정의하면 된다. Mount 되기 전에 업데이트를 하는 것은 바람직하지 않다.
해당 경우에는 componentDidMount()
를 사용하자.
클래스 컴포넌트에서 반드시 구현돼야하는 유일한 메서드이다.
이 메서드가 호출되면 this.props
와 this.state
의 값을 활용하여 아래의 것 중 하나를 반환해야 한다.
render() {
return (
<div>yeewon</div>
);
}
render()
를 통해 여러 개의 엘리먼트를 반환 render() {
const ButtonList = lists.map((data, index) => {
return (
<button key={index} type="button">
{data}
</button>
);
});
return (
// 여러 자식을 그룹화 -> 단축 문법 <></>
<Fragments>
{ButtonList}
</Fragments>
);
}
render() {
return (
{isLogin && <Login />}
);
}
주의할 점
1. render() 함수는 순수해야 한다.
순수하다 = 컴포넌트의 state를 변경하지 않고, 호출될 때마다 동일한 결과를 반환해야 한다. 브라우저와 직접적으로 상호작용 하지 않는다.
컴포넌트가 마운트된 직후, 즉 트리에 삽입된 직후에 호출된다. 데이터 구독을 설정하기 좋은 위치이다.
( New props, setState, forceUpdate ) -> render -> componentDidUpdate
업데이트는 아래 4가지 상황에서 발생한다.
1. props가 바뀔 때
2. state가 바뀔 때
3. 부모 컴포넌트가 리렌더링 될 때
4. this.forceUpdate가 강제로 렌더링을 트리거할 때
갱신이 일어난 직후에 호출된다.
componentDidUpdate(prevProps) {
// 전형적인 사용 사례 (props 비교를 잊지 마세요)
if (this.props.userID !== prevProps.userID) {
this.fetchData(this.props.userID);
}
}
주의할 점
1. componentDidUpdate()
에서 setState()
를 즉시 호출할 수도 있지만, 위의 예시처럼 조건문으로 감싸지 않으면 무한 반복이 발생할 수 있다는 점에 주의해야 한다.
2. 상위에서 내려온 prop을 그대로 state에 저장하는 것은 좋지 않으며, 그 대신 prop을 직접 사용하는 것이 좋다.
참고 자료
컴포넌트가 마운트 해제되어 제거되기 직전에 호출된다.
타이머 제거, 네트워크 요청 취소, componentDidMount() 내에서 생성된 구독 해제 등 필요한 모든 정리 작업을 수행한다.
컴포넌트 인스턴스가 마운트 해제되고 나면, 절대로 다시 마운트되지 않는다.
예시를 통해서 흐름 정리를 해보았다.
결국 마운트가 된 후 상태가 변경되면 react는 리렌더링을 한다. (render 메서드를 다시 호출한다.)
이 두번째 render는 마운트하지 않고 DOM을 업데이트한다.
function App() {
const [showUser, setShowUser] = useState(false)
return (
<div>
{showUser && <User name="Brad" />}
<button onClick={() => setShowUser(true)}>
Show User
</button>
<button onClick={() => setShowUser(false)}>
Hide User
</button>
</div>
)
}
// React starts renders our component and since this is the
// first render, it "mounts" the component to the DOM:
App()
// Then state changes and React now needs to re-render the
// component with the new state in place:
App()
// State changes again, React re-renders again:
App()
처음, App은 render되어 mount되지만 showUser가 false이므로 User는 mount되지 않는다.
이 후 showUser가 true가 되면, App은 리렌더되고 User는 처음 렌더가 되고 mount된다.
이 후 state값이 바뀌고 App이 리렌더된다. 이전 render와 비교하고, react는 마운트 되었던 User가 App의 일부가 아니게 되므로 DOM으로부터 User가 unmount된다.
각각의 컴포넌트는 자신만의 스케줄이 있다. 부모 자식 관계에서는 부모가 마운트된 경우에만 자식 컴포넌트가 render와 mount가 일어난다. 또한 부모 컴포넌트가 unmount되었을때 자식 또한 unmount된다.
마운트 과정이 constructor -> render -> componentDidMount 인데
constructor가 마운트 전, componentDidMount가 마운트 직후 이니까
결국 render메서드를 호출하는 것이 mount되는 것인가?
아니다.
render와 마운트 개념에 대해 모호해서 생긴 문제였다.
정리하면 맨 처음 컴포넌트가 render될 때는 컴포넌트가 mount되지만, props나 state가 변경되어 render될때는 mount가 되지 않는다.