Home 컴포넌트, 이미지 Preloading
Post
Cancel

컴포넌트, 이미지 Preloading

Performance

preloading이란 말 그대로 미리 로딩을 해놓는 것이다. 컴포넌트와 이미지에 대해 preloading을 할 수 있는데 하나씩 알아보도록 하겠다.



컴포넌트 preloading

가령, 아래와 같이 최적화를 위해 어떤 컴포넌트를 lazy 로딩 처리 했다고 가정해보자

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import { useState, Suspense, lazy } from 'react';

const LazyModal = lazy(() => import('./components/Modal'));

const App = () => {
  const [showModal, setShowModal] = useState(false);

  return (
    <div className='App'>
      <Suspense fallback={null}>
        {showModal ? (
          <LazyModal
            closeModal={() => {
              setShowModal(false);
            }}
          />
        ) : null}
      </Suspense>
    </div>
  );
}

export default App;

이렇게 할 경우 최초 화면에 접속했을 땐 모달 관련 파일은 바로 다운로드 받지 않고 showModal 상태의 변경에 따라 모달이 보여질 때 해당 리소스를 서버로부터 받을 것이다. 최적화는 되어 있지만 만약 해당 모달 컴포넌트가 복잡하거나 용량이 크다면 사용자가 모달 오픈 버튼을 눌렀을 때는 오히려 사용자 경험이 더 안좋아 질것이다.

그렇다면 어떻게 해결해야 할까?

이 때 preloading을 사용하는 것이다. 지금 생각해 볼 수 있는 방법은 2가지 정도다.


버튼에 마우스를 올렸을 때 로딩


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
import { useState, Suspense, lazy } from 'react';

const LazyImageModal = lazy(() => import('./components/ImageModal'));

const App = () => {
  const [showModal, setShowModal] = useState(false);

  const handleMouseEnter = () => {
    import('./components/ImageModal');
  };

  return (
    <div className='App'>
      <button
        onClick={() => {
          setShowModal(true);
        }}
        onMouseEnter={handleMouseEnter}
      >
        모달 오픈
      </button>
      <Suspense fallback={null}>
        {showModal ? (
          <LazyImageModal
            closeModal={() => {
              setShowModal(false);
            }}
          />
        ) : null}
      </Suspense>
    </div>
  );
}

export default App;


컴포넌트가 마운트 되었을 때 로딩


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
import { useState, Suspense, lazy, useEffect } from 'react';

const LazyImageModal = lazy(() => import('./components/ImageModal'));

const App = () => {
  const [showModal, setShowModal] = useState(false);

  useEffect(() => {
    import('./components/ImageModal');
  }, []);

  return (
    <div className='App'>
      <button
        onClick={() => {
          setShowModal(true);
        }}
        onMouseEnter={handleMouseEnter}
      >
        모달 오픈
      </button>
      <Suspense fallback={null}>
        {showModal ? (
          <LazyImageModal
            closeModal={() => {
              setShowModal(false);
            }}
          />
        ) : null}
      </Suspense>
    </div>
  );
}


export default App;


이렇게 했을 경우 주요 파일들이 모두 로드되고 난 이후 모달 관련된 1.chunk.js, 2.chunk.js가 차례대로 로딩 되는 것을 알 수 있다.


image



지금은 하나의 컴포넌트만 preloading 하니까 괜찮지만 나중엔 더 많은 컴포넌트들을 preloading 시켜야할 때가 올것이다. 이 때 매번 import를 하면 불편하므로 별도의 함수를 만들어서 더 쉽게 관리해보자!


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
import { useState, Suspense, lazy, useEffect } from 'react';

const lazyWithPreload = importFunction => {
  const Component = lazy(importFunction);
  Component.preload = importFunction;

  return Component;
};

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

const App = () => {
  const [showModal, setShowModal] = useState(false);

  useEffect(() => {
    LazyImageModal.preload();
  }, []);

  return (
    <div className='App'>
      <button
        onClick={() => {
          setShowModal(true);
        }}
      >
        모달 오픈
      </button>
      <Suspense fallback={null}>
        {showModal ? (
          <LazyImageModal
            closeModal={() => {
              setShowModal(false);
            }}
          />
        ) : null}
      </Suspense>
    </div>
  );
};

export default App;



이미지 preloading

이미지는 기본적으로 화면에 보여지는 시점이 아니면 로드가 되지 않는다. 그렇다면 어떻게 preloading을 할 수 있을까? 바로 자바스크립트의 Image객체를 사용하는 것이다.

1
2
3
const image = new Image();

image.src = '이미지의 주소';

이렇게 image.src에 값을 지정해주는 순간 Network 탭을 보면 이미지를 불러오는 것을 알 수 있다.

image



한 가지 주의해야할 점은 컴포넌트와 다르게 이미지는 image.src로 같은 이미지를 불러와도 네트워크 요청은 또 보낸다는 것이다. (내가 배운 내용에서는 이렇게 설명했지만 실제로 테스트를 해보니 여러번 호출하여도 한 번만 불러왔다. 일단 더 찾아보고 이에 대한 설명도 작성해보겠다.)

image

This post is licensed under CC BY 4.0 by the author.

애니메이션 최적화

문제해결 패턴 - 빈도수 세기