React.js study - 10

황유빈·2024년 7월 9일

⭐️컴포넌트 성능 최적화

주로 프로젝트의 크기가 커질수록 많은 데이터를 렌더링하게 되는데 이때 다들 랙(lag)을 경험할 수 있습니다.

이런 느려짐을 실제 눈으로는 제대로 알 수 없기에 성능을 분석하기 위해서는 다양한 도구를 사용해야 합니다.

다음은 성능을 최적화 및 분석하기 위한 도구들을 소개 합니다.

⭐️크롬 개발자 도구

React DevTools를 사용하기

리액트 v17 전에는 브라우저에 내장된 성능 측정 도구의 User Timing API를 사용했지만, v17 부터는 리액트 전용 개발자 도구인 React DevTools를 사용해야 성능 분석을 자세하게 할 수 있습니다.

프로젝트를 실행하고 개발자 도구를 열고 Component 탭에서 Profiler 탭을 열고 파란색 녹화 버튼을 한번 누르고, 이후 화면 변화가 반영되고 난 후 다시 녹화 버튼을 누르면 아래 화면과 같이 성능 분석 결과가 나타납니다.

Render duration은 리렌더링에 소요된 시간을 의미합니다.

이를 통해 소요된 시간을 확인하고 다음은 최적화 하는 방법을 알아보겠습니다.

⭐️느려지는 원인 분석

컴포넌트는 다음과 같은 상황에서 리렌더링이 발생하는데 불 필요하게 반복되는 리렌더링과 데이터가 많을 때 느려지는 원인이 됩니다.

  1. 자신이 전달받은 props가 변경될 때
  2. 자신의 state가 바뀔 때
  3. 부모 컴포넌트가 리렌더링될 때
  4. forceUpdate 함수가 실행될 때

이때 컴포넌트 리렌더링 성능을 최적화해 주는 작업으로 리렌더링을 방지해야 합니다.

React.memo

React.memo는 함수형 컴포넌트를 메모이제이션하여, props가 변경되지 않으면 컴포넌트를 리렌더링하지 않습니다. 이는 불변성을 유지하여 props의 변경을 정확히 감지할 때 유용합니다.

const MyComponent = React.memo((props) => {
  // 컴포넌트 내용
});

useState의 함수형 업데이트

const increment = () => {
    setCount(prevCount => prevCount + 1);
  };

useState 훅을 사용할 때 함수형 업데이트를 사용하면 성능을 최적화할 수 있습니다.

함수형 업데이트는 상태를 갱신할 때 직접 새로운 값을 지정하는 대신, 이전 상태를 인수로 받아 새로운 상태를 반환하는 함수를 전달하는 방식입니다. 이렇게 하면 상태 업데이트가 더 효율적으로 이루어질 수 있습니다.

성능 최적화:

  • 리액트는 상태가 변경될 때마다 컴포넌트를 다시 렌더링합니다. 함수형 업데이트를 사용하면 불필요한 상태 변경을 줄일 수 있습니다.

useReducer

useReducer는 상태와 상태를 업데이트하는 로직을 분리하여 관리할 수 있게 해주며, 특히 상태가 여러 값으로 구성된 경우에 유용합니다.

const [state, dispatch] = useReducer(reducer, initialState);

useReducer는 두 개의 인수를 받습니다:

  • reducer: 상태를 업데이트하는 함수
  • initialState: 초기 상태

또한 useReducer는 두 개의 값을 반환합니다:

  • 현재 상태 값
  • 상태를 업데이트하기 위한 dispatch 함수

성능 최적화:

  • 상태 업데이트 로직을 명확하게 정의하고, 불필요한 상태 업데이트를 방지할 수 있습니다. 또한, 상태가 복잡할수록 useReducer를 사용하면 성능 이점을 얻을 수 있습니다.

⭐️불변성의 중요성

불변성 (Immutability)이란?

불변성이란 객체나 배열 등 데이터 구조를 변경할 때 기존의 데이터를 변경하지 않고, 새로운 데이터 구조를 생성하는 것을 말합니다. 즉, 원래의 데이터를 직접 수정하지 않고, 복사본을 만들어 수정하는 방식입니다.

리액트의 리렌더링 메커니즘

리액트는 상태(state)나 속성(props)이 변경될 때마다 컴포넌트를 리렌더링합니다. 이 과정에서 리액트는 이전 상태와 새로운 상태를 비교하여 어떤 부분이 변경되었는지 확인하고, 필요한 부분만 업데이트합니다. 이를 위해 리액트는 얕은 비교(Shallow Comparison)를 사용합니다.

얕은 비교(Shallow Comparison)와 불변성

얕은 비교는 객체의 참조(레퍼런스)를 비교하는 방식입니다. 두 객체의 참조가 같다면, 객체의 내용이 동일하다고 간주합니다. 이는 매우 빠른 비교 방식입니다. 그러나 참조가 다르면, 리액트는 해당 객체가 변경되었다고 판단하여 리렌더링을 트리거합니다.

const obj1 = { a: 1, b: 2 };
const obj2 = { a: 1, b: 2 };

console.log(obj1 === obj2); // false, 객체의 참조가 다르기 때문

불변성을 유지한 상태 업데이트

불변성을 유지한다는 것은 상태를 직접 수정하지 않고, 새로운 객체나 배열을 생성하여 상태를 업데이트하는 것을 의미합니다.

불변성을 유지하면 리액트가 상태 변화를 감지하기 쉬워져 불필요한 리렌더링을 방지할 수 있습니다.

⭐️react-virtualized 최적화

  • react-virtualized는 리액트 애플리케이션에서 대규모 데이터를 효율적으로 렌더링하기 위한 라이브러리입니다.
  • 수천 개의 항목을 가진 리스트나 테이블을 렌더링할 때 성능 문제를 해결하는 데 매우 유용합니다.
  • 이 라이브러리는 가상화(virtualization) 기법을 사용하여 화면에 보이는 항목만 렌더링하고, 나머지는 필요할 때만 렌더링하여 성능을 최적화합니다.

우선 설치 방법을 알아봅시다

npm install react-virtualized

주요 컴포넌트

react-virtualized에는 여러 컴포넌트가 있지만, 가장 많이 사용되는 것은 List, Table, Grid, AutoSizer입니다.

그 중 자주 사용하는 List 를 알아봅시다.

function VirtualizedList() {
  return (
    <List
      width={300}
      height={300}
      rowCount={rowCount}
      rowHeight={20}
      rowRenderer={rowRenderer}
    />
  );
}

List 컴포넌트를 사용할 때는 해당 리스트의 전체 크기와 각 항목의 높이, 각 항목을 렌더링할 때 사용해야 하는 함수, 그리고 배열을 props로 넣어 주어야 합니다. 그러면 이 컴포넌트가 전달받은 props를 사용하여 자동으로 최적화해 줍니다.

  • react-virtualized를 사용하면 대규모 데이터를 효율적으로 렌더링하여 성능을 최적화할 수 있습니다. List, Table, Grid, AutoSizer와 같은 컴포넌트를 사용하면, 화면에 보이는 항목만 렌더링하여 성능을 크게 향상시킬 수 있습니다.
profile
초보개발자

0개의 댓글