개발(Development)/React(리액트)

[React] 컴포넌트 렌더링 과정 정리(useLayoutEffect vs. useEffect)

카레유 2022. 8. 9. 12:21

# React 컴포넌트 재렌더링 케이스

- React 컴포넌트는 아래의 2가지 상황에서 재렌더링(Re-rendering) 된다.

 

1. 내부 상태값(state)이나 중앙 상태값(redux store 등)이 변경되는 경우

2. 부모 컴포넌트가 재렌더링되는 경우, 자식 컴포넌트도 재렌더링.

 

- 컴포넌트가 렌더링되면, 해당 컴포넌트 함수가 호출되어 화면을 다시 그리는데, 이 과정을 정리해둔다.

 

 

# React 마운트 과정

1. 함수 컴포넌트 호출

2. 구현부 실행

  - props 취득, hook 실행, 내부 변수 및 함수 생성

  - 단, hook 에 등록해둔 상태값, 부수함수 효과 등은 별도 메모리에 저장되어 관리된다.

3. return 실행

  - 렌더링 시작

4. 렌더 단계(Render Phase)

  - 가상DOM을 생성한다.

5. 커밋 단계(Commit Phase)

  - 실제 DOM에 반영한다.

6. useLayoutEffect

  - 브라우저가 화면에 Paint 하기 전에, useLayoutEffect에 등록해둔 effect(부수효과함수)가 '동기'로 실행된다.

  - 이 때, state, redux store 등의 변경이 있다면 한번 더 재렌더링 된다.

7. Paint

  - 브라우저가 실제 DOM을 화면에 그린다. didMount가 완료된다.

8. useEffect

  - Mount되어 화면이 그려진 직후, useEffect에 등록해둔 effect(부수효과함수)가 '비동기'로 실행된다.

 

 

# React 재렌더링 과정

1. 함수 컴포넌트 재호출

2. 구현부 실행

  - props 취득, hook 실행, 내부 변수 및 함수 재생성

  - 단, 각 hook의 특성에 따라 기존에 메모리에 저장한 내용을 적절히 활용한다.

3. return 실행 

  - 렌더링 시작

4. 렌더 단계(Render Phase)

  - 새로운 가상DOM 생성 후, 이전 가상 DOM과 비교하여, 달라진 부분을 탐색하고, 실제 DOM에 반영할 부분을 결정한다.

5. 커밋 단계(Commit Phase)

  - 달라진 부분만 실제 DOM에 반영한다.

6. useLayoutEffect

  - 브라우저가 화면에 Paint 하기 전에, useLayoutEffect에 등록해둔 effect(부수효과함수)가 '동기'로 실행된다.

  - 이 때, state, redux store 등의 변경이 있다면 한번 더 재렌더링 된다.

7. Paint

  - 브라우저가 실제 DOM을 화면에 그린다. didUpdate가 완료된다.

8. useEffect

  - update되어 화면이 그려진 직후, useEffect에 등록해둔 effect(부수효과함수)가 '비동기'로 실행된다.

  - effect에 return부분이 있다면, 구현부보다 먼저 실행된다.

 

 

# useEffect와 useLayoutEffect

1. useEffect( 비동기effect )

- useEffect에 등록된 effect는 화면이 그려진 직후, "비동기"로 실행된다.

1) (재)렌더링 시작

2) 실제DOM에 반영

3) 화면에 Paint(didMount || didUpdate)

4) effect 함수 비동기 실행

 

 

2. useLayoutEffect ( 동기effect )

- useLayoutEffect에 등록된 effect는 실제DOM 반영 후, 화면이 그려지기 직전, "동기"로 실행된다.

1) (재)렌더링 시작

2) 실제DOM에 반영

3) effect 함수 동기 실행 : state 등 변경시, 다시 재렌더링 된다.

4) 화면에 Paint(didMount || didUpdate)

 

 

* 참고: effect "구현부"와 "return 함수" 실행 순서

- didMount => effect "구현부"만 실행

- didUpdate => effect "return 함수" 실행 => effect "구현부" 실행

- willUnmount => effect "return 함수"만 실행

 

 

# Redux store 변경시, 자동으로 재렌더링 되는 이유.

리덕스 스토어의 경우,

<Provider store={store}> 로  컴포넌트들을 감싸주면,

스토어 상태가 변경될 때마다 이를 참조하는 컴포넌트들이 재렌더링 되도록
react-redux 라이브러리가 자동으로 컴포넌트들의 렌더 함수들을 subscribe 처리 해준다. 

(개발자가 직접 subscribe 처리를 할 수도 있다.)

 

 

# 자식 컴포넌트의 불필요한 재렌더링 막는 방법

- 부모 컴포넌트가 재렌더링되면, 자식 컴포넌트들도 모두 자동으로 재렌더링된다.

- React.memo 를 사용하면, 자식이 전달받는 props가 변경되었을 때만 재렌더링 되도록 최적화할 수 있다.

 

 

# 재렌더링시, 불필요한 지역변수/함수 재생성 막는 방법

- 컴포넌트가 재렌더링되면, 해당 함수 컴포넌트가 재호출되면서 내부 변수와 함수가 다시 새로 생성된다.

- useMemo와 useCallback 훅을 사용하면, 최초 한번 생성 후 재사용 가능하다.

- 훅 사용시, 의존성배열을 추가하여 재생성 여부를 결정할 수도 있다.