TIL - Lazy Loading 적용하기

Jisu Park·2022년 12월 3일
0

오늘의개발일지-TIL

목록 보기
9/12
post-thumbnail

문제 상황 : 데이터가 날아가요..

대부분의 데이터를 redux store에 저장하고 있는 상태에서 페이지를 리로드하면 store가 초기화되는 텀이 발생한다는 것을 발견했다. 어떻게 발견했냐, 이 문제 때문에 페이지를 리로드했을 때 서버 측에서 페이지 정보를 받아올 때, null인 토큰을 보내게 되어 500 에러가 떴기 때문이다.
지금 만들고 있는 웹앱은 모바일을 기준으로 만들고 있기 때문에 페이지 리로드가 거의 발생할 일이 없긴 하지만, 만약의 경우에 리로드가 되었을 때 지금처럼 페이지에 아예 접근이 안되는 것은 말이 안된다는 생각에 이 문제를 파고들기 시작했다.

문제 해결하기

첫번 째 시도 : react-persist

처음에는 무작정 검색해서 가장 많이 해결책으로 제시되는 react-persist를 적용하려고 했다. 라이브러리를 설치하고 필요한 부분들을 고치고, 다시 시도해봤으나 결과는 동일했다. 어딘가 틀렸다는 에러도 이상한 점도 보이지 않는데 반영한 결과가 나타나지 않으니 도저히 발전시킬 수가 없었다.

두 번째 시도 : Lazy Loading

그렇게 손을 놨다가, 문득 회사 코드에서는 react-persist가 없어도 리로드 문제가 발생하지 않았다는 점이 생각났다. 그래서 부랴부랴 찾아봤더니,

const LandingPage = lazy(() => import('./pages/LandingPage'));

이런 식의 코드를 사용하고 있는 것을 발견했다. 일단 뭔지 몰라도 내 코드랑 가장 다른 점이다 싶어 바로 적용했다. 그랬더니,,

이게 왠 에러일까... 정말 눈이 빠지게 쳐다보다가 다시 회사 코드를 봤다. 뭐가 다를까. 뭐가 빠졌을까 보다 보니 의심이 가는 한 가지를 발견했다.

<Suspense fallback={ ... }>
  <Switch>
   <Route ... />
  </Switch>
</Suspense>

그래서 바아로 적용해보니! 모든 페이지가 아무 문제 없이 돌아가는 것이다! 리로드 시에도 성공적으로 페이지가 유지되었다:)

이론 짚고 넘어가기

Lazy loading

Lazy Loading은 리소스들을 중요하지 않은 데이터로 구분하고 이것들을 필요할 때만 로드하기 위한 전략입니다. 이것은 critical rendering path의 길이를 줄이는 방법으로 페이지 로드 시간을 줄일 수 있습니다.
Lazy loading은 어플리케이션에서 서로 다른 순간에 발생할 수 있지만 특히 스크롤과 네비게이션처럼 사용자 상호작용이 있을 때 발생합니다.

참고) Critical Rendering Path : The Critical Rendering Path is the sequence of steps the browser goes through to convert the HTML, CSS, and JavaScript into pixels on the screen. Optimizing the critical render path improves render performance. The critical rendering path includes the Document Object Model (DOM), CSS Object Model (CSSOM), render tree and layout.

그럼 이걸 코드로는 어떻게 반영했던 걸까?

Code Splitting

다음은 리액트 공식문서에서 코드 분할에 대해 설명한 글이다.

코드 분할은 여러분의 앱을 “지연 로딩” 하게 도와주고 앱 사용자에게 획기적인 성능 향상을 하게 합니다. 앱의 코드 양을 줄이지 않고도 사용자가 필요하지 않은 코드를 불러오지 않게 하며 앱의 초기화 로딩에 필요한 비용을 줄여줍니다.
https://ko.reactjs.org/docs/code-splitting.html#gatsby-focus-wrapper

사용하는 방법은 위에서 적어뒀으니, <Suspense/>가 필요한 이유만 짚고 넘어가야겠다. 네트워크를 통해 코드 분할 구성 요소를 가져올 때 결국 사용자가 경험해야 하는 약간의 지연이 항상 있으므로 유용한 로드 상태를 표시하는 것이 중요하다고 한다. 그렇기 때문에 리액트에서도 반드시 <Suspense/>를 사용하도록 규정해둔 것 같다.

마지막으로 <Suspense fallback={..}/>에서 fallback 안에 하나의 엘리먼트만 집어넣는 것이 아닌 다음과 같이 다양하게 customizing하여 컴포넌트를 만들 수도 있어서 사용도가 높은 것 같다. 또한 하나의 컴포넌트만 포함할 수 있는 것이 아닌 여러 컴포넌트를 감쌀 수 있어 더욱 좋다!

<Suspense
  fallback={
    <div className={`main-loading-container d-flex flex-column justify-content-center align-items-center`}>
      <div>
        <img className={`logo`} src={`/src/logo/slid_logo.png`} alt={``} />
        <img className={`logo-text`} src={`/src/logo/slid_logo_text.png`} alt={``} />
      </div>
      <div className="spinner-border mt-3" role="status">
        <span className="sr-only">Loading...</span>
      </div>
      <span className={`mt-3`}>Loading...</span>
    </div>
  }
>
   <Routes>
     <Route path="/" element={<LandingPage />} />
     <Route path="/fail" element={<NotFoundPage />}/>
     <Route path="/sign-up" element={<SignupPage />} />
     <Route path="/login" element={<LoginPage />} />
  ![](https://velog.velcdn.com/images/jisu0807/post/f980493e-e4a2-4373-8af6-18e4ca35f020/image.jpg)
</Routes>
 </Suspense>

Reference

react-persist

https://tooo1.tistory.com/572
https://okky.kr/articles/1208486
https://backend-intro.vlpt.us/6/06.html
https://velog.io/@dusunax/Redux-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EC%B4%88%EA%B8%B0%ED%99%94-%EC%9D%B4%EC%9C%A0-%ED%95%B4%EA%B2%B0%ED%95%98%EA%B8%B0
https://phsun102.tistory.com/105?category=880183

lazy-loading

https://developer.mozilla.org/en-US/docs/Web/Performance/Lazy_loading
https://scarlett-dev.gitbook.io/all/it/lazy-loading

code splitting

https://ko.reactjs.org/docs/code-splitting.html#gatsby-focus-wrapper
https://web.dev/i18n/ko/code-splitting-suspense/

profile
언젠간 데이터 분석을 하고 싶은 초짜 프론트엔드 개발자입니다🙃

0개의 댓글