React Suspense와 Lazy Loading을 통한 성능 최적화

모바일 환경에서는 네트워크 속도나 기기의 성능이 제한적일 수 있기 때문에, 로딩 성능 최적화는 더욱 중요하게 여겨집니다. 이러한 배경 속에서, React는 SuspenseLazy Loading이라는 두 가지 강력한 도구를 제공하여 초기 로드 시간을 단축시키는 데 큰 도움을 줍니다. 이 포스팅에서는 이 두 기능의 개념과 사용 방법, 그리고 이를 통해 얻을 수 있는 이점에 대해 자세히 살펴보겠습니다.


Lazy loading

Lazy Loading의 개념

Lazy Loading은 웹 애플리케이션의 성능을 향상시키는 기술 중 하나로, 웹 페이지가 처음 로드될 때 필요하지 않은 리소스(예: 이미지, 스크립트, 컴포넌트 등)를 로드하지 않는 방식입니다. 대신 해당 리소스는 사용자가 그것을 실제로 필요로 할 때 (예: 특정 섹션으로 스크롤할 때, 특정 버튼을 클릭할 때 등) 로드됩니다. 이 방식으로 초기 로딩 시간을 줄이고, 불필요한 네트워크 요청을 최소화하여 애플리케이션의 전반적인 성능을 향상시킬 수 있습니다.

전통적인 Lazy Loading 방법과의 차이점

전통적인 Lazy Loading은 주로 이미지나 큰 파일에 적용되는 기술이었습니다. 예를 들어, 웹페이지에 수많은 이미지가 있다면, 사용자가 스크롤을 내릴 때마다 새로운 이미지들이 로드되는 방식입니다. 이를 위해 자바스크립트 이벤트 리스너와 콜백 함수를 사용하여 구현되었습니다.

그러나 React에서 제공하는 Lazy Loading은 이보다 더 확장된 개념을 가지고 있습니다. React의 React.lazy() 함수는 동적으로 로딩되는 컴포넌트를 쉽게 만들어 줍니다. 이는 웹 애플리케이션에서 큰 코드베이스를 가진 컴포넌트들을 초기 로딩에서 제외시킬 수 있게 해, 초기 로딩 성능을 크게 향상시킵니다.

전통적인 Lazy Loading은 주로 네트워크와 브라우저 성능의 최적화를 위해 사용되었다면, React의 Lazy Loading은 개발자 경험과 사용자 경험을 모두 최적화하는 데 초점을 맞추고 있습니다.


React의 lazy() 함수

React.lazy()의 동작 원리

React.lazy()는 React 애플리케이션에서 코드 스플리팅을 간편하게 해주는 함수입니다. 코드 스플리팅은 큰 번들을 여러 작은 청크(chunk)로 분할하는 프로세스로, 웹 애플리케이션의 초기 로딩 시간을 줄이는 데 큰 도움을 줍니다.

React.lazy()는 동적 import를 사용하여 컴포넌트를 로드합니다. 이 함수는 default로 내보내진 컴포넌트를 반환하는 Promise를 인수로 받아들입니다. 이 Promise가 해결되면 로드된 컴포넌트가 반환됩니다. 중요한 점은, React.lazy()로 래핑된 컴포넌트는 Suspense 컴포넌트로 감싸져 있어야 합니다. 그래야 컴포넌트가 로드되기 전과 후의 UI를 적절히 처리할 수 있습니다.

Dynamic import를 활용한 컴포넌트 분리

JavaScript의 동적 import는 코드 스플리팅을 가능하게 하는 ECMAScript 제안의 일부입니다. 동적 import를 사용하면 모듈을 비동기적으로 로드할 수 있습니다. 이는 특히 큰 웹 애플리케이션에서 유용하게 작용하여, 사용자가 특정 기능에 접근할 때만 해당 코드를 로드하도록 할 수 있습니다.

React에서는 React.lazy()와 함께 동적 import를 사용하여 컴포넌트를 비동기적으로 로드합니다. 예를 들면:

const MyComponent = React.lazy(() => import('./MyComponent'));

function App() {
  return (
    <div>
      <React.Suspense fallback={<div>Loading...</div>}>
        <MyComponent />
      </React.Suspense>
    </div>
  );
}

위의 코드에서 MyComponent는 실제로 필요할 때까지 로드되지 않습니다. 사용자가 이 컴포넌트에 접근할 때만 동적 import를 통해 로드되며, 그 동안 Suspensefallback prop에 지정된 컴포넌트나 요소가 화면에 표시됩니다.

이러한 방식을 사용하면 애플리케이션의 초기 로딩 시간을 크게 줄일 수 있으며, 필요한 리소스만 로드하여 메모리 사용량도 최적화할 수 있습니다.


Suspense를 이용한 컴포넌트 로딩 처리

Suspense 컴포넌트의 동작 방식

React의 Suspense는 컴포넌트가 준비될 때까지 대기하게 하고, 그 동안 로딩 표시 등의 대체 컨텐츠를 보여줄 수 있게 해주는 컴포넌트입니다. React.lazy()로 생성된 비동기 컴포넌트와 함께 사용하면, 해당 컴포넌트가 로드되는 동안 대체 컨텐츠를 표시할 수 있게 해줍니다.

Fallback UI를 통한 로딩 상태 표현

Suspense 컴포넌트의 fallback prop을 사용하여 컴포넌트 로딩 중에 표시될 UI를 정의할 수 있습니다. 이는 사용자에게 로딩 중임을 알리거나, 기타 플레이스홀더 UI를 제공하는 데 사용됩니다.


기본적인 Suspense 사용

import React, { Suspense } from 'react';

const OtherComponent = React.lazy(() => import('./OtherComponent'));

function App() {
  return (
    <div>
      <Suspense fallback={<div>Loading...</div>}>
        <OtherComponent />
      </Suspense>
    </div>
  );
}

여기서 OtherComponent는 비동기적으로 로드됩니다. 로드되는 동안 “Loading…” 메시지가 표시됩니다.

여러 컴포넌트를 Suspense로 감싸기

import React, { Suspense } from 'react';

const ComponentOne = React.lazy(() => import('./ComponentOne'));
const ComponentTwo = React.lazy(() => import('./ComponentTwo'));

function App() {
  return (
    <div>
      <Suspense fallback={<div>Loading ComponentOne...</div>}>
        <ComponentOne />
      </Suspense>
      <Suspense fallback={<div>Loading ComponentTwo...</div>}>
        <ComponentTwo />
      </Suspense>
    </div>
  );
}

여기서 두 컴포넌트는 각기 다른 Suspense로 감싸져 있어, 각각의 로딩 상태에 따른 다른 플레이스홀더 메시지를 표시할 수 있습니다.

SuspenseList를 활용한 로딩 순서 조절

import React, { Suspense, SuspenseList } from 'react';

const ComponentA = React.lazy(() => import('./ComponentA'));
const ComponentB = React.lazy(() => import('./ComponentB'));

function App() {
  return (
    <SuspenseList revealOrder="forwards" tail="collapsed">
      <Suspense fallback={<div>Loading ComponentA...</div>}>
        <ComponentA />
      </Suspense>
      <Suspense fallback={<div>Loading ComponentB...</div>}>
        <ComponentB />
      </Suspense>
    </SuspenseList>
  );
}

SuspenseList를 사용하면 여러 Suspense 컴포넌트의 reveal 순서나 로딩 표시를 조절할 수 있습니다.

SuspenseReact.lazy()를 함께 사용하면 코드 스플리팅을 쉽게 구현할 수 있으며, 사용자 경험을 크게 향상시킬 수 있습니다.


여러 컴포넌트에서의 Suspense 활용

여러 Lazy 컴포넌트의 동시 로딩

React에서 여러 lazy 컴포넌트를 사용할 때, 이 컴포넌트들을 동시에 로드하고 싶을 수 있습니다. Suspense의 바깥쪽에서 여러 lazy 컴포넌트를 그룹화하면, 이러한 동시 로딩을 달성할 수 있습니다.

다양한 Fallback UI 전략

Lazy 컴포넌트 로딩 중에 어떤 UI를 사용자에게 보여줄 것인지 결정하는 것은 중요합니다. Fallback UI는 사용자에게 컴포넌트가 아직 준비되지 않았음을 알리며, 앱의 반응성을 유지하는 데 도움을 줍니다.

여러 Lazy 컴포넌트의 동시 로딩

import React, { Suspense } from 'react';

const ComponentOne = React.lazy(() => import('./ComponentOne'));
const ComponentTwo = React.lazy(() => import('./ComponentTwo'));

function App() {
  return (
    <div>
      <Suspense fallback={<div>Loading components...</div>}>
        <ComponentOne />
        <ComponentTwo />
      </Suspense>
    </div>
  );
}

위의 예제에서 두 컴포넌트는 동일한 Suspense로 감싸져 있으므로, 두 컴포넌트가 동시에 로드될 것입니다.

다양한 Fallback UI 전략

import React, { Suspense } from 'react';

const UserProfile = React.lazy(() => import('./UserProfile'));
const UserPosts = React.lazy(() => import('./UserPosts'));

function App() {
  return (
    <div>
      <Suspense fallback={<div>Loading user profile...</div>}>
        <UserProfile />
      </Suspense>
      <Suspense fallback={<div>Loading user posts...</div>}>
        <UserPosts />
      </Suspense>
    </div>
  );
}

위의 예제에서 각 컴포넌트는 서로 다른 fallback UI를 갖게 됩니다. 이렇게 함으로써 사용자는 각 컴포넌트의 로딩 상태를 명확하게 알 수 있게 됩니다.

다양한 Fallback UI 전략을 통해 사용자 경험을 향상시킬 수 있습니다. 컴포넌트의 로딩 상태를 사용자에게 명확하게 전달하면, 사용자는 앱이 반응하고 있다는 것을 알 수 있습니다.


실제 애플리케이션에서의 적용 사례

대형 프로젝트에서의 성능 향상 사례

대형 애플리케이션에서 페이지 별로 여러 컴포넌트와 모듈을 로드해야 할 때, 초기 로딩 시간이 길어질 수 있습니다. React Suspense와 Lazy Loading은 이러한 문제를 해결하는 데 큰 도움이 됩니다.

한 대형 쇼핑몰 웹사이트의 경우, 상품 상세 페이지, 장바구니, 결제 페이지 등 여러 다른 섹션으로 구성됩니다. 각 섹션은 다양한 외부 라이브러리나 컴포넌트를 사용하게 될 수 있습니다. Suspense와 Lazy Loading을 적용하여 필요할 때만 해당 섹션의 컴포넌트와 라이브러리를 로드함으로써 초기 페이지 로딩 속도를 크게 향상시켰습니다.

주의점 및 팁

  1. Fallback 디자인: 사용자에게 로딩 중임을 알리는 Fallback UI는 사용자 경험에 중요한 역할을 합니다. 너무 간단하거나 너무 복잡한 Fallback은 사용자에게 혼란을 줄 수 있습니다. 따라서, Fallback 디자인에는 신경을 써야 합니다.
  2. Error Boundaries: Lazy 컴포넌트 로딩 중 오류가 발생할 경우를 대비하여 Error Boundaries를 적용하는 것이 좋습니다. 이를 통해 사용자에게 의미 있는 오류 메시지를 제공할 수 있습니다.
  3. 네트워크 상태 고려: 느린 네트워크 환경에서는 컴포넌트 로딩에 시간이 더 걸릴 수 있습니다. 이를 고려하여 Fallback UI의 표시 시간을 조절하거나, 사용자에게 네트워크 상태에 따른 추가적인 안내를 제공하는 것이 좋습니다.
  4. SuspenseList 사용: 여러 lazy 컴포넌트의 로딩 순서를 제어하려면 SuspenseList를 활용할 수 있습니다. 이를 통해 여러 컴포넌트의 로딩 순서를 정의하거나, 동시에 로드되도록 설정할 수 있습니다.

실제 애플리케이션에서는 다양한 요소와 상황을 고려해야 합니다. 따라서 Suspense와 Lazy Loading을 적용할 때는 애플리케이션의 전체 구조와 사용자 경험을 함께 고려하여 최적의 성능과 사용자 경험을 달성해야 합니다.


마치며

React의 세계는 끊임없이 발전하고 있습니다. 그 중에서도 Suspense와 Lazy Loading은 최근의 주요 업데이트 중 하나로, 애플리케이션의 성능을 크게 향상시키는 도구로 자리잡았습니다. 이러한 기술은 초기 페이지 로딩 속도를 개선하고, 사용자 경험을 풍부하게 만드는 데 크게 기여하게 됩니다.

본 포스팅을 통해 Suspense와 Lazy Loading의 기본적인 개념과 활용 방법에 대해 알아보았습니다. 하지만 이 두 기술이 제공하는 기능은 이보다 훨씬 더 많습니다. 그러므로 꾸준한 학습과 연습을 통해 이를 최대한 활용하는 것이 중요합니다.

앞으로도 React는 계속해서 발전할 것입니다. 그만큼 우리 개발자들도 새로운 기술과 변화에 유연하게 대응할 준비가 되어있어야 합니다. 이 글이 React 개발에 있어 한 걸음이라도 도움이 되었기를 바랍니다.

마지막으로, 프론트엔드 개발은 단순히 코드를 작성하는 것만이 아닙니다. 사용자에게 최적의 경험을 제공하기 위해 여러 가지 방면에서의 노력이 필요합니다. Suspense와 Lazy Loading은 그 중 하나일 뿐입니다. 다양한 도구와 기술을 꾸준히 학습하며, 항상 사용자 중심의 개발을 목표로 해야 합니다.

다음 포스팅에서는 또 다른 흥미로운 주제로 만나뵙겠습니다. 그때까지, 행복한 코딩 되세요! 🚀🌟

Leave a Comment