관리 메뉴

Jerry

리액트 최적화 요약집👍👍 (useCallback, useMemo ...) 본문

Front/React

리액트 최적화 요약집👍👍 (useCallback, useMemo ...)

juicyjerry 2021. 4. 8. 02:12
반응형

 필자는 현재 코드스테이츠 Immersive 수료 후에 취업 준비 과정 중에 있다. 취업 준비 과정에서 리액트에 다시 개념 공부도 하고 있기도 하고 스터디원들과 기술 면접 리스트를 가지고 준비하는 과정에서 이번에 "리액트 최적화"라는 주제가 내 눈길을 사로잡아 이번 기회로 잘 정리해보려고 한다.

 

 이번 주제와 관련해서 공식 문서와 여러 잘 정리된 블로그 글들을 보고 너튜브 영상도 찾아서 보았다.

참고한 자료들을 나름 집대성해보려고 했으나 양이 비대해지는 걸 막지 못해 핵심적인 부분 위주로 구성을 해보았다. 

각 내용의 자세한 내용들을 참고한 자료의 출처에 대한 내용들을 보시면 더 이해가 잘 될 것이다.

 

만약, 한 번 보고 이해가 안 가신다면 그건 당연하다고(?) 말씀드리고 싶고 꼭 필자의 글만 볼 필요 없고 구글링을 통해 

여러 다양한 레퍼런스들을 참고하면서 여러번 보면 이해가 점점 될 것이라 말씀드리고 싶다. 서두가 길었다. 시작해보겠다!

 


본론에 들어가기 앞서 몇 가지 미리 알면 좋을 간단한 질문을 내보겠다! 

 


1. 리액트 최적화란 무슨 뜻일까?

 

최적화(Optimization)

Optimization is a program transformation technique, which tries to improve the code by making it consume less resources (i.e. CPU, Memory) and deliver high speed.

출처: tutorialspoint | URL: bit.ly/3fPaGQt

 

 

해석하자면, 최적화란 프로그램 변현 기술로 코드를 이용하여 CPU, 메모리의 리소스가 적게 소모시키며 속도도 향상해주도록 하는 것이라고 한다. 리액트 최적화는 리액트 기술을 활용하여 관련 코드를 이용한 성능 개선을 시켜준다고 정리할 수 있을 것 같다. 

 

 

 

2. 데이터를 업데이트 하는 과정에서 불변성을 지켜야 되는데 그 이유가 무엇일까?

 

예를 들어 아래 예시는 한 번쯤 겪어봤거나 코드로 구현해봤거나 해볼 것이다.

부모 컴포넌트와 자식 컴포넌트가 있다고 가정해보자. (혹은 상위 컴포넌트와 하위 컴포넌트)
(이하 부모 컴포넌트는 '부모', 자식 컴포넌트는 '자식'이라고 통칭함)

 

부모에서 자식으로 전달하는 데이터(props)가 있다. 부모에서 자식으로 input tag나 form tag로 받은 입력 값을 받아 전달한다. 

이런 상황에서  자식에 console.log 코드를 추가해서 찍히는 값을 확인해보자. 그러면 부모에서만 렌더링을 해주면 되지만 자식까지 리렌더링(재실행)이 되는 걸 볼 수 있다.


즉, 자식 컴포넌트에 부모 컴포넌트에서 해당 데이터가 생기거나 할 경우 자식 컴포넌트까지 렌더링이 된다는 것이다.

 

이런 상황은 Virtual DOM에만 리 렌더링을 해주어 큰 문제가 일어나지 않는다고 한다. 하지만 최악의 조건인 상황이나 관련 데이터들이 한 번에 수백 개씩 혹은 그 이상이라면 성능 손실이 발생하며 이는 렌더링에서 수행하는 로직이 많을수록, 많은 컴포넌트를 출력할수록 손실을 커질 것이다.

 

위 문제에 대한 2가지 해결 방법을 먼저 소개하자면 shouldComponentUpdate & React.PureComponent 생태주기 메서드를 사용하면 된다. 아참! 위 질문의 답은 우리가 위 메서드를 활용하게 되면 필요한 경우에만 렌더링이 되는데 그 이유가 우리가 불변성을 지켜주었다고 보면 된다고 한다! (자세한 내용은 velpert 글을 참고)

 

shouldComponentUpdate를 정의하면 컴포넌트 렌더링을 제어할 수 있다. 데이터가 변경되어 필요한 경우에만 렌더링 작업을 수행할 수 있다고 한다.
React.PureComponent는 변경되는 데이터가 모두 원시 값이거나 불변성(shallow equal, 얕은 비교를 통해 렌더링 결정함)을 보장할 수 있을 때 사용할 수 있다고 한다. 또한, React.Component에 shouldComponentUpdate 생태주기 메서드가 장착돼 있다고 생각하면 된다고 한다. 

 

(더 자세한 내용은 옆에 참고)👉👉👉👉👉👉

참고: velopert blog | URL: bit.ly/3rWWCXC    

참고: Vingle Tech Blog | URL: bit.ly/31QLqRX

 

 

 


 

리액트에서는 렌더링이 되는 대표적인 조건이 몇 가지 있다. 

 

  1. state 변경이 있을 때
  2. 부모 컴포넌트가 렌더링 될 때
  3. 새로운 props이 들어올 때
  4. shouldComponentUpdate에서 true가 반환될 때
  5. forceUpdate가 실행될 때

 

이 중에서 1번과 2번은 얕은 비교를 통해 새로운 값인지 여부를 따져 리렌더링을 한다고 한다.

참고로 클래스 컴포넌트에서는 렌더링이 될 경우, render 메서드만 리 렌더링이 되지만, 함수형 컴포넌트(훅스)에서는 위 조건 중에 하나라도 될 경우 함수 전체가 재실행이 된다.  

 

이제부터 이야기할 useCallback과 useMemo가 지금까지 이야기한 불필요한 리 렌더링에 관해 최적화할 수 있도록 도움을 줄 것이다.


useCallback과 useMemo

1. useMemo: 복잡한 함수 결괏값을 기억 (함수의 리턴값을 기억) // useRef: 일반 값을 기억

 

사용하는 이유

useCallback 사용만으로는 하위 컴포넌트의 리렌더를 막을 수 없다! 하위 컴포넌트가 참조 동일성에, 의존적인, 최적화된 Purecomponent! 이어야만 비로소 불필요한 리 렌더링을 막을 모든 것이 완성된다.

React.memo은 shouldComponentUpdate라이프 사이클이 기본으로 내장된 함수형 컴포넌트라고 생각하면 된다. 얕은 비교 연산을 통해 동일한 참조 값의 prop이 들어온다면 리 렌더링을 방지시킨다.

 

어떻게 사용할까?

고차 컴포넌트이므로 사용 중인 component를 memo로 감싸주기만 하면 된다.
또한 props에 대해 기본으로 제공되는 얕은 비교가 아닌 커스텀을 하고 싶다면 두 번째 인자로 비교 함수를 넣어 사용할 수 있다.

 

간단하게 이야기 해보면, useMemo는 메모리제이션된 값을 반환한다 라는 리액트 공식 문서의 한 문장으로 요약할 수 있을 것 같다. 

 

 

 

2. useCallback: 함수 자체를 기억하고 있음

 

사용하는 이유

현재 하위 컴포넌트에 전달하는 콜백 함수를 inline 함수로 사용하고 있다거나, 컴포넌트 내에서 함수를 생성하고 있다면 (프로그래밍 구동에는 문제가 없겠지만) 새로운 함수 참조 값을 계속해서 만들고 있는 것, 다시 말해 똑같은 모양의 함수를 계속해서 만들어 메모리에 계속해서 할당하고 있다는 것을 뜻한다.

 

의존성에 포함된 값이 변경되지 않는다면 이전에 생성한 함수 참조 값을 반환해주는 것이 useCallback이다.

 

어떻게 사용할까?

인라인 콜백과 그것의 의존성 값의 배열을 전달하세요. useCallback은 콜백의 메모이제이션된 버전을 반환할 것이다. 그 메모이제이션된 버전은 콜백의 의존성이 변경되었을 때에만 변경된다. 이것은, 불필요한 렌더링을 방지하기 위해 (예로 shouldComponentUpdate를 사용하여) 참조의 동일성에 의존적인 최적화된 자식 컴포넌트에 콜백을 전달할 때 유용하다.

 

자식컴포넌트에 함수를 넘길 때 무조건 useCallback를 적용시켜줘야 한다. 자식 입장에서는 부모가 매번 새로운 함수를 주는 것이라고 판단한다고 한다.

 

useEffect에서 제2의 인자로 의존성 배열 안에 값이 존재할 경우 => componentDidUpdate
useEffect에서 제2의 인자로 의존성 배열로 빈 배열로 존재할 경우 => componentDidMount 

: 위의 useEffect 와 useCallback이 동작하는 방식이 유사하다.

 

간단하게 이야기 해보면, useCallback은 메모리제이션된 함수를 반환한다 라는 리액트 공식 문서의 한 문장으로 요약할 수 있을 것 같다. 

 

 

3. 조심해야할 점

 

함수 생성자체가 비용이 클 경우, 클릭 이벤트처럼 여러 번 누를 경우에  기억을 잘해서 처음 찍혔단 값을 계속 가지고 있는다.

그래서 두번째 인자에 배열 안으로 같이 넣어줘야 한다. (useEffect와 유사 방식)

  • useMemo, useCallback, useEffect가 2번째 인자가 중요하다. 어느 시점에 실행이 될지 정해주기 때문에.

 

 

(더 자세한 내용은 옆에 참고)👉👉👉👉👉👉👉

참고: 제로초 | URL: youtu.be/6H6KncvVc8s

참고: yejinh.log | URL: bit.ly/3cVD95f          

참고: 이화랑 블로그 | URL: bit.ly/3wD66uE  

반응형

'Front > React' 카테고리의 다른 글

리렌더링이란? 🤷‍♂️🤷‍♂️  (0) 2021.04.09
Virtual DOM 이란🧐🧐  (0) 2021.04.09
#Sprint  (0) 2020.12.02
#1. react 익숙해지기  (0) 2020.11.30
리액트와 1일  (0) 2020.11.20