Menu

리액트 생명주기: 마운트, 업데이트, 언마운트

모든 React 컴포넌트는 마운트되고(나타나고), 업데이트되고(다시 렌더링되고), 언마운트됩니다(제거됩니다). 각 단계가 useEffect에 어떻게 대응하는지, 클래스 생명주기 메서드와 그에 대응하는 훅, 그리고 렌더링 단계와 커밋 단계를 배웁니다.

이 페이지에는 실행 가능한 에디터가 있습니다 - 편집하고 실행하면 결과를 바로 볼 수 있습니다.

React 컴포넌트 생명주기에는 세 단계가 있습니다. 마운트(컴포넌트가 처음으로 화면에 나타남), 업데이트(state, props, 컨텍스트가 바뀌어 다시 렌더링됨), 언마운트(제거됨)입니다. 함수 컴포넌트에서는 useEffect로 이 단계들에 반응합니다. []를 가진 이펙트는 마운트 후에 실행되고, 의존성을 가진 이펙트는 그 의존성이 바뀐 업데이트 후에 실행되며, 이펙트가 반환하는 함수는 언마운트 시에 실행됩니다.

미리보기 아래의 콘솔이 각 단계가 일어나는 대로 보여 줍니다.

콘솔은 render, count = 0과 mounted로 시작합니다. Count를 클릭할 때마다 렌더링과 업데이트가 기록됩니다. Unmount는 unmounted를 기록하고, Mount again은 컴포넌트와 함께 state가 버려졌으므로 count = 0부터 다시 시작합니다.

마운트

컴포넌트는 React가 트리의 특정 위치에서 처음 렌더링할 때 마운트됩니다. React는 함수를 호출하고, 반환된 JSX로 DOM 노드를 만들어 삽입하고, 브라우저가 그리게 한 다음, 컴포넌트의 이펙트를 실행합니다.

useEffect(fn, [])는 컴포넌트가 화면에 있는 동안 계속 존재해야 하는 것을 시작하는 곳입니다. 구독, 타이머, 연결, 첫 데이터 요청 같은 것들입니다. 그린 뒤에 실행되므로 첫 프레임을 절대 늦추지 않습니다.

업데이트

컴포넌트는 다음 경우에 업데이트됩니다(다시 렌더링됩니다).

  • 자기 state가 바뀔 때,
  • 부모가 다시 렌더링될 때(기본적으로 props가 바뀌었든 아니든 모든 자식도 렌더링됩니다),
  • 읽는 컨텍스트가 바뀔 때.

업데이트마다 React는 의존성이 바뀐 이펙트를 실행합니다. 이펙트를 다시 실행하기 전에 그 이펙트의 이전 클린업을 실행하므로, 새 구독이 열리기 전에 이전 구독이 닫힙니다. 렌더링 페이지에서 렌더링을 일으키는 것을 더 자세히 다룹니다.

언마운트

컴포넌트는 부모가 더 이상 그것을 렌더링하지 않을 때(위의 {show && <Counter />}처럼), key가 바뀔 때, 또는 루트 자체가 언마운트될 때 언마운트됩니다. React는 DOM 노드를 제거하고, 모든 이펙트의 클린업을 실행하고, state를 버립니다. 나중에 컴포넌트가 다시 나타나면 완전히 새로운 인스턴스입니다.

부모와 자식

React는 위에서 아래로 렌더링하지만 이펙트는 아래에서 위로 실행합니다. 부모와 자식이 함께 마운트되면 자식의 이펙트가 먼저 실행되므로, 부모의 이펙트는 자식이 완전히 준비되었다고 믿을 수 있습니다.

마운트는 render Parent, render Child, Child effect, Parent effect를 기록합니다. Remove를 누르면 클린업이 반대 순서로 실행됩니다. Parent cleanup, 그다음 Child cleanup입니다.

렌더링 단계와 커밋 단계

모든 업데이트는 두 단계를 거칩니다.

  1. 렌더링 단계. React가 새 JSX를 계산하기 위해 컴포넌트를 호출하고 이전 결과와 비교합니다. 아직 화면에서는 아무것도 바뀌지 않습니다. React는 이 작업을 멈추거나, StrictMode에서 두 번 실행하거나, 버릴 수 있으며, 그래서 렌더링은 순수해야 합니다. 요청, 구독, 바깥 변수 변경이 없어야 합니다.
  2. 커밋 단계. React가 차이를 DOM에 적용하고, ref를 연결하고, useLayoutEffect 콜백을 실행합니다. 모두 브라우저가 그리기 전입니다. useEffect 콜백은 그 뒤, 보통 브라우저가 그린 다음에 실행됩니다. 클릭이나 다른 개별 입력이 업데이트를 일으켰다면, React는 다음 이벤트 전에 결과가 준비되도록 대신 레이아웃 이펙트 직후에 바로 실행합니다.

클릭할 때마다 같은 순서로 세 줄이 기록됩니다. 이 이펙트들에는 의존성 배열이 없으므로 렌더링마다 실행됩니다. 둘 다 두 번째 인자로 []를 추가하면 첫 렌더링 후에만 실행됩니다.

클래스 생명주기 메서드와 대응하는 훅

클래스 컴포넌트는 생명주기를 이름 있는 메서드로 나타냅니다. 오래된 코드와, 여전히 클래스가 필요한 에러 바운더리에서 보게 됩니다.

클래스 메서드실행 시점함수 컴포넌트에서의 대응
constructor첫 렌더링 전 한 번useState(initial), useRef
static getDerivedStateFromProps렌더링마다 그 전에렌더링 중에 값을 계산하거나 key로 초기화
render렌더링마다함수 본문
componentDidMount첫 렌더링이 DOM에 들어간 뒤useEffect(fn, [])
shouldComponentUpdate업데이트 전, 건너뛸 수 있음React.memo(반대의 답을 반환: "props가 같은가")
getSnapshotBeforeUpdateDOM이 바뀌기 직전직접 대응하는 훅 없음, ref와 useLayoutEffect가 가장 가까움
componentDidUpdate업데이트마다 그 뒤useEffect(fn, [deps])(마운트 후에도 실행)
componentWillUnmount제거 전useEffect가 반환하는 클린업
getDerivedStateFromError, componentDidCatch자식이 오류를 던질 때없음: 에러 바운더리 클래스를 작성

다음은 실행되는 모든 메서드를 기록하는 클래스입니다.

마운트는 constructor, getDerivedStateFromProps, render, componentDidMount를 기록합니다. 클릭은 getDerivedStateFromProps, shouldComponentUpdate, render, getSnapshotBeforeUpdate, componentDidUpdate를 기록합니다. shouldComponentUpdate가 false를 반환하게 하면 클릭해도 버튼이 업데이트되지 않습니다. state는 바뀌지만 React가 렌더링을 건너뜁니다. 클래스 컴포넌트 페이지에서 이런 클래스를 함수로 바꾸는 방법을 보여 줍니다.

생명주기가 아니라 동기화로 생각하세요

훅 표는 오래된 코드를 읽을 때 유용하지만, 큰 "마운트됨" 이펙트 하나와 큰 "업데이트됨" 이펙트 하나처럼 클래스 습관을 그대로 옮긴 이펙트를 쓰게 만들 수 있습니다. 이펙트는 "이 바깥의 것을 이 값들과 동기화하라"로 읽는 편이 낫습니다. roomId에 연결하고, roomId가 바뀌면 연결을 끊고 다시 연결합니다. 동기화하는 대상마다 이펙트를 하나씩 쓰고, 사용하는 값을 의존성으로 나열하고, 언제 실행할지는 React가 정하게 하세요.

자주 묻는 질문

React 컴포넌트 생명주기에는 어떤 단계가 있나요?

마운트(React가 컴포넌트를 만들고 그 출력을 화면에 놓음), 업데이트(state, props, 컨텍스트가 바뀌어 다시 렌더링됨), 언마운트(제거되면서 정리함)입니다.

componentDidMount에 대응하는 훅은 무엇인가요?

useEffect(() => { ... }, [])입니다. 빈 의존성 배열 때문에 첫 렌더링이 화면에 나온 뒤 한 번만 실행됩니다. 이펙트가 반환하는 함수가 componentWillUnmount에 해당합니다.

componentDidUpdate에 대응하는 훅은 무엇인가요?

[userId]처럼 관심 있는 값을 의존성 배열에 넣은 useEffect입니다. componentDidUpdate와 달리 첫 렌더링 후에도 실행되므로 마운트와 업데이트를 함께 다룹니다.

부모와 자식의 이펙트는 어떤 순서로 실행되나요?

React는 부모에서 아래로 렌더링하지만, 이펙트는 자식에서 위로 실행합니다. 자식의 이펙트가 부모의 이펙트보다 먼저 실행됩니다. 언마운트 시에는 부모의 클린업이 자식의 클린업보다 먼저 실행됩니다.

렌더링 단계와 커밋 단계란 무엇인가요?

렌더링 단계에서 React는 화면이 어떻게 보여야 하는지 알아내기 위해 컴포넌트를 호출하며, 이 작업을 멈추거나 버릴 수 있습니다. 커밋 단계에서는 변경 사항을 DOM에 적용하고 레이아웃 이펙트를 실행합니다. 일반 이펙트는 그 뒤, 보통 브라우저가 그린 다음에 실행됩니다.

Coddy 프로그래밍 언어 일러스트

Coddy로 코딩 배우기

시작하기