웹 애플리케이션의 성능 최적화는 사용자 경험에 직접적인 영향을 미치는 중요한 요소입니다. 특히 컴포넌트 로딩 전략은 초기 로딩 시간과 전반적인 애플리케이션 성능에 큰 영향을 줍니다. 이 글에서는 두 가지 주요 로딩 전략인 Lazy Loading과 Preloading의 적절한 사용 케이스를 구분하여 살펴보겠습니다.
Lazy Loading은 컴포넌트나 리소스를 실제로 필요할 때까지 로딩을 지연시키는 기술입니다. 이 방식은 초기 로딩 시간을 단축시키고 필요한 리소스만 로드하여 성능을 최적화합니다.
초기 화면에 보이지 않는 컴포넌트
조건부로 렌더링되는 컴포넌트
큰 용량의 라이브러리를 사용하는 컴포넌트
라우트 기반 컴포넌트
// 모달 컴포넌트 지연 로딩 예시
import React, { lazy, Suspense, useState } from 'react';
// 모달 컴포넌트를 lazy loading으로 불러옴
const ModalWindow = lazy(() => import('./ModalWindow.js'));
function App() {
const [isModalVisible, setIsModalVisible] = useState(false);
return (
<div>
<button onClick={() => setIsModalVisible(true)}>모달 열기</button>
{/* 모달이 필요할 때만 로딩 */}
{isModalVisible && (
<Suspense fallback={<div>로딩 중...</div>}>
<ModalWindow onClose={() => setIsModalVisible(false)} />
</Suspense>
)}
</div>
);
}
이 예시에서는 사용자가 '모달 열기' 버튼을 클릭할 때만 ModalWindow 컴포넌트가 로드됩니다. 이는 초기 로딩 시간을 단축시키고, 필요할 때만 리소스를 사용하게 합니다
Preloading은 사용자가 특정 컴포넌트나 리소스를 요청하기 전에 미리 로드하는 기술입니다. 이 방식은 사용자가 실제로 컴포넌트를 요청했을 때 즉시 표시할 수 있어 사용자 경험을 향상시킵니다.
사용자가 곧 방문할 가능성이 높은 라우트
자주 사용되는 중요 컴포넌트
초기 로딩 후 백그라운드에서 로드할 수 있는 컴포넌트
네트워크 상태가 좋을 때 미리 로드할 컴포넌트
React에서 Preloading을 구현하는 방법은 여러 가지가 있습니다. 가장 일반적인 방법들을 살펴보겠습니다.
import React, { lazy, Suspense, useState } from 'react';
// lazyWithPreload 함수 구현
function lazyWithPreload(importFunction) {
const Component = lazy(importFunction);
Component.preload = importFunction;
return Component;
}
// 모달 컴포넌트를 lazyWithPreload로 불러옴
const ModalWindow = lazyWithPreload(() => import('./ModalWindow.js'));
function App() {
const [isModalVisible, setIsModalVisible] = useState(false);
return (
<div>
<button
onClick={() => setIsModalVisible(true)}
onMouseEnter={() => ModalWindow.preload()} // 마우스 호버 시 미리 로드
>
모달 열기
</button>
{isModalVisible && (
<Suspense fallback={<div>로딩 중...</div>}>
<ModalWindow onClose={() => setIsModalVisible(false)} />
</Suspense>
)}
</div>
);
}
이 예시에서는 사용자가 버튼 위에 마우스를 올렸을 때 ModalWindow.preload()를 호출하여 컴포넌트를 미리 로드합니다. 사용자가 버튼 위에 마우스를 올리고 클릭하기까지의 시간(약 0.2~0.5초)을 활용하여 컴포넌트를 미리 로드함으로써 클릭 시 즉시 표시할 수 있습니다.
import React, { lazy, Suspense, useState, useEffect } from 'react';
// lazyWithPreload 함수 구현
function lazyWithPreload(importFunction) {
const Component = lazy(importFunction);
Component.preload = importFunction;
return Component;
}
// 모달 컴포넌트를 lazyWithPreload로 불러옴
const ModalWindow = lazyWithPreload(() => import('./ModalWindow.js'));
const HeavyComponent = lazyWithPreload(() => import('./HeavyComponent.js'));
function App() {
const [isModalVisible, setIsModalVisible] = useState(false);
// 컴포넌트 마운트 후 백그라운드에서 미리 로드
useEffect(() => {
// 페이지 로드 후 중요 컴포넌트 미리 로드
ModalWindow.preload();
// 네트워크 상태가 좋을 때만 추가 컴포넌트 로드
if (navigator.connection && navigator.connection.effectiveType === '4g') {
HeavyComponent.preload();
}
}, []);
return (
<div>
<button onClick={() => setIsModalVisible(true)}>
모달 열기
</button>
{isModalVisible && (
<Suspense fallback={<div>로딩 중...</div>}>
<ModalWindow onClose={() => setIsModalVisible(false)} />
</Suspense>
)}
</div>
);
}
이 예시에서는 useEffect를 사용하여 컴포넌트가 마운트된 후 백그라운드에서 중요 컴포넌트를 미리 로드합니다. 또한 네트워크 상태를 확인하여 좋은 상태일 때만 추가 컴포넌트를 로드하는 조건부 로딩도 구현할 수 있습니다.
import React, { useState } from 'react';
import { preload } from 'react-dom';
function App() {
const [showComponent, setShowComponent] = useState(false);
// 컴포넌트에서 사용할 리소스 미리 로드
preload("https://example.com/important-font.woff2", { as: "font" });
preload("https://example.com/critical-script.js", { as: "script" });
return (
<div>
<button onClick={() => setShowComponent(true)}>
컴포넌트 표시
</button>
{showComponent && <ImportantComponent />}
</div>
);
}
React 18에서 도입된 preload API를 사용하면 폰트, 스크립트, 스타일시트 등 컴포넌트에서 사용할 리소스를 미리 로드할 수 있습니다. 이는 컴포넌트가 렌더링되기 전에 필요한 리소스를 미리 준비하여 렌더링 속도를 향상시킵니다.
로딩 전략을 선택할 때는 다음 요소들을 고려해야 합니다:
사용자 행동 패턴
리소스 크기와 복잡성
네트워크 환경
애플리케이션 특성
Lazy Loading과 Preloading은 상호 배타적인 전략이 아니라 상호 보완적인 전략입니다. 초기 로딩 시간을 최소화하기 위해 Lazy Loading을 적용하고, 사용자 경험을 향상시키기 위해 중요한 컴포넌트는 Preloading하는 균형 잡힌 접근 방식이 이상적입니다
최적의 로딩 전략은 애플리케이션의 특성, 사용자 행동 패턴, 그리고 비즈니스 요구사항에 따라 달라질 수 있으므로, 실제 사용자 데이터와 성능 측정을 기반으로 지속적으로 최적화하는 것이 중요합니다