React 컴포넌트 최적화 개요
React 컴포넌트 최적화는 성능을 향상시키고 앱의 반응성을 개선하는데 중요한 역할을 합니다. 최적화를 통해 불필요한 렌더링을 방지하고 자원을 효율적으로 활용할 수 있습니다.
렌더링과 최적화
렌더링은 React 앱에서 UI 갱신을 처리하는 과정입니다. 컴포넌트가 렌더링될 때마다 가상 돔(Virtual DOM)을 비교하여 변경된 부분을 갱신합니다. 하지만 모든 렌더링은 비용이 발생하므로 불필요한 렌더링을 최소화하는 것이 중요합니다.
컴포넌트 최적화 방법
React 컴포넌트를 최적화하는 방법은 여러 가지가 있습니다. 다음은 대표적인 방법들입니다.
1. 불필요한 렌더링 방지하기
2. PureComponent와 memo를 이용한 성능 개선
3. 메모이제이션을 이용한 성능 개선
4. 가상화와 이중 렌더링 방식 이해하기
5. React.memo를 이용한 성능 개선
6. React.lazy와 Suspense를 이용한 지연 로딩 처리
7. 리스트와 키(Key)의 중요성 이해하기
8. 이벤트 핸들러 최적화하기
9. useMemo와 useCallback을 이용한 성능 개선
// 예시 코드
import React, { PureComponent } from 'react';
class MyComponent extends PureComponent {
render() {
return (
컴포넌트 내용
...
);
}
}
불필요한 렌더링 방지하기
불필요한 렌더링을 방지하여 성능을 향상시킬 수 있습니다. React에서 불필요한 렌더링이 발생하는 경우는 크게 두 가지로 나눌 수 있습니다.
1. Props나 State가 변경되지 않았을 때의 렌더링
shouldComponentUpdate를 사용하여 Props나 State의 변경 여부를 확인하고, 변경이 없을 경우 렌더링을 하지 않도록 할 수 있습니다.
// 예시 코드
import React, { Component } from 'react';
class MyComponent extends Component {
shouldComponentUpdate(nextProps, nextState) {
if (this.props.someProp === nextProps.someProp && this.state.someState === nextState.someState) {
return false;
}
return true;
}
render() {
return (
컴포넌트 내용
...
);
}
}
2. 불필요한 자식 컴포넌트의 렌더링
자식 컴포넌트에서도 불필요한 렌더링이 발생할 수 있습니다. 이 경우는 부모 컴포넌트의 렌더링이 발생하지 않았는데도 자식 컴포넌트가 렌더링되는 경우입니다. 이를 방지하기 위해 React.memo를 사용할 수 있습니다.
// 예시 코드
import React, { memo } from 'react';
const MyComponent = memo(({ prop1, prop2 }) => {
return (
컴포넌트 내용
...
);
});
PureComponent와 memo를 이용한 성능 개선
React에서는 PureComponent와 memo를 사용하여 성능을 개선할 수 있습니다. 이들은 얕은(shallow) 비교를 통해 불필요한 렌더링을 방지하는 역할을 합니다.
PureComponent
PureComponent는 React.Component를 상속받은 클래스입니다. PureComponent를 사용하면 shouldComponentUpdate를 구현하지 않아도 Props나 State의 얕은 비교를 자동으로 수행하여 변경된 값이 있는 경우에만 렌더링이 발생합니다.
// 예시 코드
import React, { PureComponent } from 'react';
class MyComponent extends PureComponent {
render() {
return (
컴포넌트 내용
...
);
}
}
memo
memo는 함수형 컴포넌트를 감싸는 고차 컴포넌트입니다. memo를 사용하면 이전에 렌더링된 결과를 기억하여 Props가 변경되지 않았을 경우에만 렌더링을 수행합니다.
// 예시 코드
import React, { memo } from 'react';
const MyComponent = memo(({ prop1, prop2 }) => {
return (
컴포넌트 내용
...
);
});
메모이제이션을 이용한 성능 개선
메모이제이션을 이용하여 함수의 결과를 저장하고 재사용함으로써 성능을 개선할 수 있습니다. React에서는 useCallback과 useMemo를 사용하여 메모이제이션을 구현할 수 있습니다.
useCallback
useCallback은 함수를 기억하고 재사용할 수 있게 해줍니다. 의존성 배열을 인자로 받아 변경되지 않으면 이전에 생성된 함수를 반환합니다.
// 예시 코드
import React, { useCallback } from 'react';
const MyComponent = () => {
const handleClick = useCallback(() => {
// 버튼 클릭 시 동작
}, []);
return (
);
};
useMemo
useMemo는 계산된 값을 기억하고 재사용할 수 있게 해줍니다. 의존성 배열을 인자로 받아 변경되지 않으면 이전에 생성된 값을 반환합니다.
// 예시 코드
import React, { useMemo } from 'react';
const MyComponent = ({ prop1, prop2 }) => {
const calculatedValue = useMemo(() => {
// 계산된 값
return prop1 + prop2;
}, [prop1, prop2]);
return (
{calculatedValue}
);
};
가상화와 이중 렌더링 방식 이해하기
가상화(Virtualization)는 대규모 데이터 목록을 렌더링할 때 성능을 개선하기 위한 방법입니다. 이중 렌더링(Double Rendering)은 가상화를 구현하기 위한 방식 중 하나입니다.
가상화
가상화는 큰 데이터 목록을 작은 단위로 나누어 화면에 보여주는 방식입니다. 화면에 보이는 부분만 렌더링하고 나머지는 가상화된 상태로 유지하여 불필요한 렌더링을 최소화합니다.
예시로 React에서는 react-virtualized나 react-window와 같은 라이브러리를 사용하여 가상화를 구현할 수 있습니다. 이러한 라이브러리는 스크롤 가능한 리스트나 테이블과 같은 컴포넌트들을 최적화된 방식으로 렌더링합니다.
이중 렌더링
이중 렌더링은 효율적인 가상화 구현을 위해 사용되는 방식 중 하나입니다. 이 방식은 두 개의 컨테이너를 사용하여 화면에 표시할 컨텐츠와 실제로 렌더링되는 컨텐츠를 분리합니다.
첫 번째 컨테이너인 가상화 컨테이너는 화면에 보이는 내용을 가상화하여 빠르게 스크롤 및 검색 기능을 제공합니다. 이 컨테이너는 실제 DOM 요소를 가지지 않고 가상화된 상태로 유지됩니다.
두 번째 컨테이너인 렌더링 컨테이너는 화면에 표시되어야 할 실제 컨텐츠를 렌더링합니다. 이 컨테이너는 화면에 보이는 영역에 해당하는 데이터만을 불러와서 렌더링하므로 효율적인 렌더링이 가능합니다.
이중 렌더링은 사용자가 스크롤하여 가상화 컨테이너에서 보고자 하는 컨텐츠를 선택하면 해당 컨텐츠가 렌더링 컨테이너로 이동하여 화면에 표시됩니다. 이 과정에서 가상화 컨테이너와 렌더링 컨테이너의 데이터가 동기화되어 화면에 빠르게 업데이트됩니다.
이중 렌더링은 react-window 라이브러리와 같은 가상화 라이브러리에서 사용되는 방식입니다.
React.memo를 이용한 성능 개선
React.memo는 함수형 컴포넌트의 성능을 개선하기 위해 사용되는 React의 기능입니다. 이를 사용하면 컴포넌트의 프로퍼티(props)가 변경되지 않는 한 이전에 렌더링된 결과를 재사용할 수 있습니다.
React.memo는 컴포넌트의 출력 결과를 메모이제이션하여 동일한 프로퍼티가 주어졌을 때 이전에 렌더링한 결과를 재사용합니다. 이를 통해 불필요한 렌더링을 피하고 성능을 향상시킬 수 있습니다.
예시 코드
// 예시 함수형 컴포넌트
import React from 'react';
const MyComponent = React.memo(({ prop1, prop2 }) => {
// 컴포넌트의 렌더링 코드
return (
{prop1}
{prop2}
);
});
위의 예시 코드에서 MyComponent는 React.memo로 감싸져 있습니다. 이로 인해 MyComponent의 prop1과 prop2가 이전에 렌더링된 결과와 동일하다면 이전 결과를 재사용하고, 동일하지 않다면 컴포넌트를 다시 렌더링합니다.
React.memo를 사용하여 컴포넌트를 메모이제이션하면, 상위 컴포넌트가 리렌더링되어도 MyComponent는 프로퍼티가 변경되지 않을 경우에만 이전 결과를 재사용하여 성능을 개선합니다.
React.lazy와 Suspense를 이용한 지연 로딩 처리
React.lazy와 Suspense는 React 16.6 이후에 도입된 기능으로, 지연 로딩 처리를 쉽게 구현할 수 있게 해줍니다. 이를 사용하면 필요한 컴포넌트가 실제로 필요할 때까지 불러오지 않고, 필요한 시점에서 비동기적으로 로딩할 수 있습니다.
예시 코드
// 예시로 사용할 다이나믹 임포트 함수
const OtherComponent = React.lazy(() => import('./OtherComponent'));
// 예시 컴포넌트
function MyComponent() {
return (
Loading... }>