늘 겸손하게

React - 리액트 렌더링 성능 향상을 위해 할 수 있는 일 본문

Programming/React

React - 리액트 렌더링 성능 향상을 위해 할 수 있는 일

besforyou999 2022. 7. 30. 13:11

리액트 렌더링 성능을 향상 시키기 위해서는 Component가 렌더링 되는 것을 최소한으로 해야한다.

 

CPU 자원을 가장 많이 사용하는 것이 렌더링이기 때문에 가능한 렌더링 횟수를 줄이는것이 렌더링 성능 향상에 핵심 요소.

 

렌더링 횟수를 줄이는 방법을 알아보자.

 

 

1. 메모이제이션

 

메모이제이션이란, 반복적인 계산을 피하기 위해 계산 결과를 메모리에 저장해두고 같은 계산을 하려고하면 저장해둔 계산 결과를 재활용하는 최적화 기술입니다. 이 기술을 이용해 변경사항이 없는 컴포넌트가 반복적으로 렌더링되는것을 막을 수 있습니다.

 

리액트로 메모이제이션을 사용할 수 있는 키워드 입니다.

 

  • useMemo
  • useCallback
  • React.memo

 

https://besforyou.tistory.com/249

 

React - React.memo, useCallback, useMemo

useCallback, useMemo useCallback, useMemo 모두 React 최적화를 위해 사용되는 훅입니다. useCallback은 메모이제이션된 콜백(함수)을 반환하고 useMemo는 메모이제이션된 값을 반환합니다. 메모이제이션? Memo..

besforyou.tistory.com

 

 

2. Array.map에서 key값으로 index 사용하지 않기

 

배열에 저장된 데이터들을 map을 이용해 컴포넌트로 생성할 때( 컴포넌트 매핑 ) key값을 추가하지 않으면 React는 경고문을 날립니다.

 

이때 key값으로 index를 사용할 경우 콘솔에 보이는 Warning은 없어지지만 좋지 않은 방법이라고 합니다.

 

 

<이유>

 

React가 DOM 요소를 구분하는데 사용하는 유일한 데이터가 key값입니다. index로 key값을 설정했다고 가정합시다.

 

만약 리스트(배열) 중간에 데이터를 삽입하거나 제거하면? React는 같은 key로도 원하는 컴포넌트를 찾아내지 못하거나 추가된 데이터 개수는 적지만 많은 데이터들의 key값이 달라져 불필요하게 많은 리렌더링이 발생할 수 있기 때문입니다

 

 

위 내용이 렌더링 성능 향상과 어떤 상관이 있는걸까요?

 

 

자식에 대한 재귀적 처리

 

React는 이전 가상 DOM과 현재 가상 DOM을 비교하고 변경된 점이 있는 경우에 변경된 부분만 리렌더링합니다. 아래 코드와 같이 자식 노드의 끝에 요소를 추가하면 변경점은 하나뿐이니 많은 렌더링이 발생하지 않습니다.

 

 

// 이전
<ul>
  <li>first</li>
  <li>second</li>
</ul>

// 현재
<ul>
  <li>first</li>
  <li>second</li>
  <li>third</li>   <--- 유일한 변경점
</ul>

 

 

하지만 아래와 같은 트리는 렌더링이 많이 발생합니다. 추가된 데이터는 한 가지뿐이지만 트리를 전부 다시 렌더링해야합니다.

 

 

// 이전
<ul>
  <li>Duke</li>
  <li>Villanova</li>
</ul>

// 현재
<ul>
  <li>Connecticut</li>       <-- Duke 와 다름
  <li>Duke</li>              <-- Villanova 와 다름
  <li>Villanova</li>         <-- 새로 추가된 요소
</ul>

 

 

 

이러한 문제를 해결하기 위해 React는 key 속성을 지원합니다. 자식들이 key를 가지고 있다면, React는 key를 통해 기존 트리와 이후 트리의 자식들이 일치하는지 확인합니다. 위 예시에 key를 추가하여 트리의 변환 작업이 효율적으로 수행되도록 수정할 수 있습니다.

 

 

 

// 이전
<ul>
  <li key="2015">Duke</li>
  <li key="2016">Villanova</li>
</ul>

// 현재
<ul>
  <li key="2014">Connecticut</li>
  <li key="2015">Duke</li>
  <li key="2016">Villanova</li>
</ul>

 

 

이제 React는 '2014' key를 가진 요소가 새로 추가되었고, 다른 요소는 이동만 하면 되는것을 알 수 있습니다.

 

이러한 key값으로 배열의 인덱스를 사용할 수 있지만, 배열이 재배열될 경우 각 요소의 key값도 변경되니 위 이점을 누리지 못할것입니다.

또한 컴포넌트 state와 관련된 문제가 발생할 수 있습니다.

 

예로, 위 예시에서 key를 인덱스값으로 한다면

 

 

// 이전
<ul>
  <li key="0">Duke</li>
  <li key="1">Villanova</li>
</ul>

// 현재
<ul>
  <li key="0">Connecticut</li>
  <li key="1">Duke</li>
  <li key="2">Villanova</li>
</ul>

 

이전에 key = 0 인 요소과 현재 key = 0인 요소는 다릅니다. 하지만 React는 그 차이를 구분하지 못하여 컴포넌트의 state가 엉망이 되거나 의도하지 않은 방식으로 바뀔 수도 있습니다.

 

 

3. React.PureComponent

 

PureComponent는 순수 컴포넌트로 같은 입력값에 대해 늘 같은 출력값을 반환하는 순수함수처럼 같은 props와 state에 대해 동일한 결과를 렌더링하는 컴포넌트라고 할 수 있습니다.

 

PureComponent는 내부에는 shouldComponentUpdate() 생명 주기 메소드가 이미 구현되어 있습니다.

 

shouldComponentUpdate() 메소드가 True를 반환하면 render() 함수가 호출되어 컴포넌트가 리렌더링되는데

 

PureComponent는 props와 state를 이전의 props와 state와 shallow compare(얕은 비교)하여 차이점이 있는 경우에만

 

render() 함수에 True를 반환합니다. 이 방식으로 불필요한 리렌더링을 줄여 성능 향상을 얻을 수 있습니다.

 

 

https://besforyou.tistory.com/245

 

React - Pure component

React에서 지원하는 컴포넌트중에는 Pure component 라는 컴포넌트가 존재한다. Pure component에 대해 알아보자. React.PureComponent Pure component란 순수 컴포넌트로 같은 입력값에 대해 늘 같은 출력값을..

besforyou.tistory.com

 

 

shallow compare ( 얕은 비교 )

 

  • 스칼라 값 ( numbers, strings )은 값을 비교한다
  • Object(객체) 비교는 reference(주소)를 비교한다

 

 

 

 

요약 

  • 메모이제이션
  • index로 컴포넌트 매핑 피하기
  • PureCompoennt 사용

 

 

 

출처

https://robinpokorny.medium.com/index-as-a-key-is-an-anti-pattern-e0349aece318

https://ko.reactjs.org/docs/reconciliation.html#recursing-on-children

https://velog.io/@shin6403/React-%EB%A0%8C%EB%8D%94%EB%A7%81-%EC%84%B1%EB%8A%A5-%EC%B5%9C%EC%A0%81%ED%99%94%ED%95%98%EB%8A%94-7%EA%B0%80%EC%A7%80-%EB%B0%A9%EB%B2%95-Hooks-%EA%B8%B0%EC%A4%80