인프런 커뮤니티 질문&답변

Luke님의 프로필 이미지
Luke

작성한 질문수

프론트엔드 개발자를 위한, 실전 웹 성능 최적화(feat. React) - Part. 1

2-6) 컴포넌트 Preloading

Factory pattern에 대해서 궁금한 점이 있습니다

작성

·

297

2

function lazyWithPreload(importFunction) {
  const Component = lazy(importFunction);
  Component.preload = importFunction;
  return Component;
}

const LazyImageModal = lazyWithPreload(() => import("./components/ImageModal"));

이 부분에 대해서 여러번 생각을 해봐도 코드의 동작 방식이 잘 이해가 되지 않는데요, importFunction에 의해서 lazy하게 로딩되는 Component를 반환하는 것은 알겠는데, preload를 통해서 importFunction을 다시 넣어주고 그 함수를 useEffect에서 다시 호출을 해준다는 개념이 좀 어색합니다. 

preload를 호출함으로써 importFunction이 호출되는데, 그 결과가 Component에 담기는 거라면 const Component = lazy(importFunction) 이 하는 역할이 뭘까요..?

개념이 잘 이해가 안되다보니까 질문도 굉장히 중언부언하게 되네요... 

저 팩토리 패턴에 대해서 조금 더 자세하게 설명해주실 수 있을까요?

답변 2

4

유동균님의 프로필 이미지
유동균
지식공유자

안녕하세요, Luke님,

Component의 Preloading 코드에 대해서 질문을 주셨는데요, 해당 내용은 저렇게 꼭 써야한다는 것이 아니라 레이지 로딩하는 코드가 많아 지게 되면 위와 같은 펙토리 패턴으로 효율적으로 동적 로딩 컴포넌트들을 관리할 수 있다는 관점에서 얘기한거라 조금 헷갈리셨을 수도 있다고 생각합니다.

 

이해를 돕기 위해 굳이 함수를 사용하지 않고 표현해보면 다음과 같습니다.

// 단순 컴포넌트 동적 로딩 코드 (이렇게 하면 Suspense 안에서 해당 컴포넌트가 사용되는 순간 import가 됩니다.)
const LazyImageModal = lazy(() => import("./components/ImageModal"));

// 위 코드만 쓰게되면 단순 코드 분할 및 지연 로딩 일뿐 preloading을 한 건 아니죠?
// 그래서 해당 컴포넌트가 실제 사용되기 이전 시점에 import(즉, preload)하기 위해서는
// 적절한 시점에 단순 컴포넌트를 import하는 코드가 필요합니다.
// 그 작업을 해주는 코드를 펙토리 패턴 적용 전에는 useEffect에서 직접 import 구문을 호출해줬는데,
// 이제는 미리 import 구문을 해당 컴포넌트에 preload라는 커스텀 속성을 만들어 넣어줬습니다.
// 이렇게 하면, useEffect 안에서 직접 import를 호출할 필요없이,
// LazyImageModal.preload(); 이렇게만 호출하면 됩니다.
LazyImageModal.preload =
() => import("./components/ImageModal");

위 코드에 주석으로 코드에 대한 설명을 드렸습니다.

아마 제 생각에는 컴포넌트가 동적 로딩되는 과정에서 이해가 안 되신거 같아 추가적인 설명을 드리자면,

lazy(() => import()) 를 하는 순간 컴포넌트가 import 되는 것이 아닙니다.
해당 코드는 특정 컴포넌트(또는 모듈)을 동적으로 로드 하겠다는 표시이고 번들 파일에서 분할(코드 분할)합니다.
그리고 Suspense 안에서 해당 모듈이 사용되는 순간 분할된 코드를 로드하여 실행을 하는 방식입니다.

하지만, 우리가 원하는건 사용되는 순간 분할된 코드를 로드하는 것이 아닌, 사용하기 전 시점에 미리 코드를 로드하여 사용하는 순간에는 딜레이(분할된 코드가 다운로드되는 시간)없이 사용하고자 하는 것입니다.

그것을 위해서는 동적으로 파일을 로드하는 코드인 import 구문을 직접 호출해줘야합니다.
이것은 lazy에서 호출하는 import와 다릅니다. lazy 안의 import 구문은 해당 컴포넌트가 사용되는 시점에 해당 코드를 자동으로 로드하기 위해 사용되는 코드이고, 지금 얘기하는 직접 호출하는 import는 해당 컴포넌트가 사용될지와 상관없이 그냥 로드하는 겁니다.

이렇게하면, 해당 코드는 다운로드되고 시간이 지나 실제 해당 코드를 사용하는 순간이 오면 굳이 새로 다운로드 하지 않아도 기존에 다운로드된 코드를 그대로 활용할 수 있게됩니다. 즉, 딜레이가 사라지는 거죠.

코드에서 LazyImageModal.preload 에 import 구문을 넣는 것은 그것을 위한 것이고,
useEffect에서 LazyImageModal.preload()를 호출하는 것은 preload를 위해 import 구문을 직접 실행하여 코드를 미리 로드해 두기 위함입니다.

 

답변이 도움되셨길 바라며, 강의에 관심을 가져주셔서 감사합니다. :)

 

Luke님의 프로필 이미지
Luke
질문자

말씀해주신 내용을 천천히 읽어보니 이해가 되는 것 같습니다. lazy import 과정에 대해서 상세하게 설명해주셔서 감사합니다! 

0

Luke님의 프로필 이미지
Luke
질문자

혹시 반환된 Component가 아직 resolve되지 않은 상태로 껍데기(?)만 DOM tree에 들어있다가 preload로 넣어준 import()가 실행되면서 로드되어 렌더되는 건가요? 

Luke님의 프로필 이미지
Luke

작성한 질문수

질문하기