렌더링되어 컴포넌트가 DOM에 붙는 순간에 특정 동작을 하게 만들 수 있다.
(index.js에서 root에 접근하여 ReactDOM.render()하는) render() 함수가 실행되어 리액트가 jsx를 DOM에 붙여주는 딱 그 순간!😝에 실행될 동작을 구현한다.
처음 실행되는 render()가 성공적으로 실행(컴포넌트가 첫❗ 렌더링)된 후 componentDidMount()
가 실행된다.
즉, 컴포넌트가 화면에 보이자마자 실행될 동작을 작성한다.
그러나 setState로 리렌더링되고나서는 componentDidMount()는 실행되지 않는다.
📍주의! render() 안에서 setState를 사용하면 무한 렌더링되기 때문에 문제가 발생되므로 setState를 쓰고 싶을 때는 componentDidMount() 안에서 사용한다.
componentDidMount()에서 했던 작업을 제거하는 용도로, 컴포넌트가 제거되기 직전에 componentWillUnmount()
가 실행된다.
자식 컴포넌트 입장에서 부모 컴포넌트가 자신을 제거할 때 실행된다.
componentDidMount()와 componentWillUnmount()는 짝꿍!💑
componentDidMount()가 첫번째 렌더링에서만 실행된다면, componentDidUpdate()
는 setState가 실행되거나 props가 변경되는 경우처럼 '리렌더링'된 후에 실행된다.
✨ Class Component일 때의 LifeCycle(라이프사이클) 과정
constructor → render → (ref) → componentDidMount
(경우 1) setState 또는 props 바뀔 때 → shouldComponentUpdate(true 리턴) → componentDidUpdate
(경우 2) 부모가 나(자식 컴포넌트)를 제거할 때 → componentWillUnmout → (자식 컴포넌트) 소멸
보통 componentDidMount()
에 비동기 요청(ex. setInterval, setTimeout) 을 하고, componentWillUnmount()
에서 비동기 요청을 취소(ex. clearInterval, clearTimeout) 한다.
해당 컴포넌트가 사라졌다해도 비동기 요청을 제거하지 않으면 계속 실행된다.
컴포넌트가 삭제되었다가 추가될 때마다 그만큼 비동기 요청이 추가되어 실행되는 비동기 요청이 많아지는 문제가 발생된다.
그리고 계속해서 메모리를 차지하므로 메모리 누수가 발생된다.
그러므로 완료되지 않은 비동기 요청은 componentWillUnmount()에서 반드시 정리한다.(필수!)
(참고. 자바스크립트 관련 클로저 문제)
비동기 함수가 밖에 선언한 변수를 참조하면 클로저 문제가 발생한다. 함수 안에서 참조할 수 있도록 하기!
- ✨리액트에서 많이 쓰이는 패턴!
메서드 안에 함수를 호출하는 경우 아래와 같이 두가지 방법으로 사용할 수 있다. (빈 화살표 위치 주의!)
실무에서는 함수를 연달아서 쓰는 고차함수(HOF) 패턴의 방식을 많이 볼 수 있다.onClickBtn = (choice) => { ... } <button onClick={() => this.onClickBtn('가위')}가위</button> // 또는 간단하게 만들고 싶다면 고차함수로 작성 onClickBtn = (choice) => () => { ... } <button onClick={this.onClickBtn('가위')}가위</button>
useEffect(() => { // componentDidMount, componenetDidUpdate 역할
return () => { // componentWillUnmount 역할
...
}
}, []);
함수형 컴포넌트의 경우, 라이프사이클을 사용하지 않지만 useEffect
Hook를 사용하여 'componentDidMount'와 'componentDidUpdate'의 역할을 대체할 수 있다. (완전하게 1대1 대응하는 것은 아님)
useEffect() 안에 함수의 return문이 'componentWillUnmount' 역할을 대신한다.
즉, useEffect가 주요 라이프사이클 3가지를 한번에 처리하는 것이다.
useEffect도 useState와 useRef와 마찬가지로 함수 컴포넌트 안에 작성한다.
useEffect의 인자
구분 | 클래스 컴포넌트의 LifeCycle | 함수형 컴포넌트의 Hooks |
---|---|---|
문법 | componentDidMount componentWillUnmount componentDidUpdate | useEffect |
렌더링 시 | componentDidMount, componentDidUpdate 실행 | 전체 실행 |
state 관리 | 라이프사이클 각각 전체 state를 관리 | 한개 또는 여러개의 state 관리 (effect가 상이한 각각의 useEffect 작성) |
// start, end, result 로 state 설정한 경우,
componentDidMount() { // start, end, result 통째로!
this.setState({
start: '시작',
end: '끝',
result: '결과',
})
}
useEffect(() => { // start 또는 end 또는 result
setStart();
setEnd();
}, [start, end]);
useEffect(() => { // start 또는 end 또는 result
setResult();
}, [result]);
📌 라이프사이클과 비교하여 useEffect 패턴 암기하기!
- 함수 컴포넌트는 매번 다시 실행되는 특성이 있다.
클래스 컴포넌트의 라이프사이클에서는 componentWillUnmount가 실행되지 않지만, 함수형 컴포넌트의 useEffect에서는 두번째 인자인 배열 안에 값이 바뀔 때마다 전체가 실행된다.
(setInterval 실행/종료를 반복하여 마치 setTimeout과 같은 효과)- state마다 다른 effect를 낼 수 있기 때문에 useEffect를 여러번 쓸 수 있다.
클래스 컴포넌트의 경우 componentDidMount나 componentDidUpdate에서 모든 state를 조건문으로 분기 처리한다.
*출처: Youtube ZeroCho TV 리액트 기본 강좌