React.memo 심층 분석
React.memo 심층 분석
React.memo로 감싼 컴포넌트는 주변의 State에 영향을 받지 않고 변경될 경우에만 re-render됩니다.
사용법
- component : 컴포넌트를 넣으면 메모화됩니다.
- arePropsEqual : prevProps와 newProps 두가지 인수를 받는 함수입니다. 일반적으로 이 함수는 지정하지 않습니다.
- return : component를 반환합니다.
React.memo의 컴포넌트 비교
memo는 props가 이전과 같지 않을 경우 다시 렌더링합니다.
props의 비교는 Object.is()를 사용하며 결과는 이러합니다. 3 = 3, {} ≠ {}
얕은 비교
자바스크립트에서는 reference types를 비교할 수 없습니다.
참조타입은 함수, 배열, 객체가 있는데 비교할 수 없는 이유는 참조라는 말 그대로 메모리에 할당하여 그 메모리를 참조하는 타입으로 서로가 다른 메모리를 참조하기 때문입니다.
React.memo에서 참조 타입 해결법
useMemo : props가 객체, 배열일 경우
useCallback : props가 함수일 경우
React.memo를 사용해보며 컴포넌트를 렌더링에서 어떻게 제외시키는 지가 궁금해져서 찾아보게되었습니다.
React.memo는 내부적으로 어떻게 동작 할까?
memo 함수
- type : ReactElement
- compare : arePropsEqual
컴포넌트가 없을 경우 개발자모드에서 에러를 발생시킵니다.
return
- typeof를 추가해서 리턴합니다. 이 컴포넌트가 어떤 컴포넌트인지 $$typeof 프로퍼티를 통해 설명합니다
- REACT_MEMO_TYPE
어떻게 재조정과정에서 제외되는 거지?
먼저 간단하게 Fiver를 생성할 것같은 파일부터 보겠습니다.
ReactFiber.js github link
파이버노드를 생성하는 함수가 맞습니다.
간단하게 fiber를 생성하며 아까 보았던 type(REACT_MEMO_TYPE)을 태그로 지정하는 것을 알 수 있습니다.
memo fiber가 어떤 식으로 생성되는 지 알았으니 재조정 과정을 찾아보기위에 beginwork에 접근해보겠습니다. beginwork가 업데이트를 수집하는 과정에서 React.memo 컴포넌트는 제외 될 것이라 예상됩니다.
ReactFiberBeginWork.js github link
current : 참조용 Fiber
workInProgerss : 작업중인 Fiber
renderLanes : 렌더링 레인 - 업데이트의 우선순위와 타이밍을 알려줌.
updateMemoComponent : 메모 컴포넌트 업데이트 함수
updateSimpleMemoComponent : 단순한 메모 컴포넌트 업데이트 함수
핵심 함수1 : updateMemoComponent
updateMemoComponent란?
- 컴포넌트가 초기렌더링인지, 간단한 컴포넌트인지, 업데이트가 필요한지 여부를 순서대로 보고 최대한 적은 비용으로 업데이트를 합니다.
- 간단한 컴포넌트: defaultProps가 없고, arePropsEqual를 사용하지 않았으며 함수형 컴포넌트라면 간단한 컴포넌트로 취급합니다. 간단한 컴포넌트는 updateSimpleMemoComponent 라는 함수를 호출하여 컴포넌트를 간단하게 비교하고 리턴합니다.
- 기존 혹은 변경될 컴포넌트를 리턴합니다.
핵심 함수2 : checkScheduledUpdateOrContext
checkScheduledUpdateOrContext란?
- 업데이트가 있는지 확인하는 함수입니다.
- 현재 컴포넌트의 Lanes에 보류중인 업데이트가 있는 지 확인합니다.
- 컨텍스트의 변화가 있는지 확인합니다.
code
- 첫 렌더링인가?
current : 현재 렌더링되어있는 컴포넌트입니다. 이 컴포넌트가 없다면 처음으로 마운트되고 있음을 의미합니다.
1-1. 단순한 컴포넌트인가?
1-2. 단순한 파이버 생성
- 개발자 모드
- checkPropTypes : props 타입을 검사합니다. 아마 오류나 경고를 띄워주는 용도인 듯합니다.
- facebook/react/packages/shared/checkPropTypes.js
- defaultProps : 이제 지원하지 않는 기능이므로 사용을 권장하지 않는다는 error 메세지를 띄워줍니다.
- checkPropTypes : props 타입을 검사합니다. 아마 오류나 경고를 띄워주는 용도인 듯합니다.
- 초기 렌더링이 아닐경우?
3-1. checkScheduledUpdateOrContext : 업데이트 혹은 컨텍스트 변화가 있는 지 확인합니다.
3-2. 업데이트가 없을 경우 한번 더 확인하고 업데이트를 벗어납니다.
3-3. 업데이트가 있을 경우
함수 정리
bailoutOnAlreadyFinishedWork
facebook/react/packages/react-reconciler/src/ReactFiberBeginWork.js
- 이미 완료된 작업은 업데이트를 벗어납니다.
shallowEqual
- Props를 얕은 비교로 비교합니다.
정리
- React.memo로 컴포넌트를 감싸면 type$$ 프로퍼티가 생기는데 해당 프로퍼티가 컴포넌트를 구별하는 용도로 사용됩니다.
- 메모 컴포넌트는 변경사항이 있다면 beginwork에서 변경된 컴포넌트를 리턴합니다. 만약 변경사항이 없다면 기존의 컴포넌트를 리턴합니다.
- 메모 컴포넌트는 단순한 컴포넌트라면 더욱 빨리 일을 처리합니다. 단순한 컴포넌트란 defalutProps, arePropsEqual 기능을 사용하지 않고 함수형 컴포넌트여야합니다.
- 우리가 여기서 알 수 있는 것은 해당 기능들을 사용하지 않으면 조금 더 빠른 렌더링을 할 수 있다는 것입니다.
- enableLazyContextPropagation 변수를 통해 컨텍스트 변경사항이 있는지 확인하거나 Lanes로 업데이트 사항이 있는 지 확인하여 업데이트를 할지 안할지 결정합니다.
- 만약 업데이트가 없다면 자식 컴포넌트의 업데이트에 접근하고 그것도 없다면 업데이트를 중지합니다.
더 알아봐야할 것
- 재조정과정 중 Lanes의 역할
- 직접 만들어본다면?
출처 :
Tejas Kumar, Fluent React, O’Reilly Media, [Common Questions And Powerful Patterns]

