Code Split[React]

SnowCat·2023년 2월 22일
0
post-thumbnail
  • Webpack, Rollup, Browerify같은 툴을 사용해 여러 파일을 병합한 번들된 파일을 웹페이지에서 로드할 수 있음
    ex)
// app.js
import { add } from './math.js';

console.log(add(16, 26));

// math.js
export function add(a, b) {
  return a + b;
}

// bundle
// 실제로는 엄청 다르게 나옴
function add(a, b) {
  return a + b;
}

console.log(add(16, 26));

코드 분할

  • 앱의 크기가 커지게 되면 변들의 규모가 커지게 됨
  • 특히 크기가 큰 서드파티 라이브러리를 추가하면 앱의 크기가 커져 로드 시간이 길어지기도 함
  • 번들이 커지는 것을 방지하기 위해 여러 번들을 동적으로 만들고 불러오는 것이 필요함
  • 코드 분할을 통해 앱을 지연로딩할 수 있게 해주고, 앱 사용자 입장에서는 앱의 성능 향상이 되게 해줌

import()

  • import를 지연시키는 방법을 통해 앱에 코드 분할을 도입할 수 있음
import("./math").then(math => {
  console.log(math.add(16, 26));
});
  • 웹팩이 이 구문을 만나게 되면 코드 분할이 가능함

React.lazy

  • React.lazy 함수를 사용하면 컴포넌트가 렌더링 될 때 나머지 번들을 불러오게 됨
  • React.lazy 함수에서는 동적 import를 호출하는 함수를 인자로 가지고, 이 함수는 React 컴포넌트를 default export로 가져야 함
const OtherComponent = React.lazy(() => import('./OtherComponent'));
  • lazy 컴포넌트는 예비 컨텐츠를 보여주는 suspense 컴포넌트 안에서 렌더링 되야 함
import React, { Suspense } from 'react';

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

// fallback: 컴포넌트가 로드될 때 까지 출력할 element
function MyComponent() {
  return (
    <div>
      <Suspense fallback={<div>Loading...</div>}>
        <OtherComponent />
        <AnotherComponent />
      </Suspense>
    </div>
  );

fallback을 피하는 법

  • lazy 컴포넌트를 로딩하게 되면 기존에 존재하던 Suspense 내부의 컴포넌트들까지 일시적으로 보이지 않는 문제가 발생하게 됨
import React, { Suspense } from 'react';
import Tabs from './Tabs';
import Glimmer from './Glimmer';

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

// Tab 컴포넌트를 클릭하게 되면 화면이 전환됨
// 화면이 전환될 때 기존에 있던 Photo, Component 창이 일시적으로 사라지게 됨
function MyComponent() {
  const [tab, setTab] = React.useState('photos');
  
  function handleTabSelect(tab) {
    setTab(tab);
  };
	
  return (
    <div>
      <Tabs onTabSelect={handleTabSelect} />
      <Suspense fallback={<Glimmer />}>
        {tab === 'photos' ? <Photos /> : <Comments />}
      </Suspense>
    </div>
  );
}

Error boundaries

  • 에러 처리가 필요한 경우 Error Boundary를 Suspense 위에 감싸 네트워크 문제가 생겼을 때 에러를 표시할 수 있음
import React, { Suspense } from 'react';
import MyErrorBoundary from './MyErrorBoundary';

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

const MyComponent = () => (
  <div>
    <MyErrorBoundary>
      <Suspense fallback={<div>Loading...</div>}>
        <section>
          <OtherComponent />
          <AnotherComponent />
        </section>
      </Suspense>
    </MyErrorBoundary>
  </div>
);

Route-based code splitting

  • 앱의 코드 분할을 시도하 경우 라우트에서부터 코드 분할을 하는 것을 권장
    페이지 전환시 웹 페이지를 불러오는 시간은 필연적으로 발생하게 됨
    보통 페이지를 한번에 렌더링하기 때문에 렌더링 동안 다른 요소와도 상호작용할일이 없음
import React, { Suspense, lazy } from 'react';
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';

const Home = lazy(() => import('./routes/Home'));
const About = lazy(() => import('./routes/About'));

const App = () => (
  <Router>
    <Suspense fallback={<div>Loading...</div>}>
      <Routes>
        <Route path="/" element={<Home />} />
        <Route path="/about" element={<About />} />
      </Routes>
    </Suspense>
  </Router>
);

Named Exports

  • default exports 이외에 named exports를 사용하고자 하면 default로 이름을 재정의한 중간 모듈을 생성해 주어야 함
// ManyComponents.js
export const MyComponent = /* ... */;
export const MyUnusedComponent = /* ... */;

// MyComponent.js
export { MyComponent as default } from "./ManyComponents.js";

// MyApp.js
import React, { lazy } from 'react';
const MyComponent = lazy(() => import("./MyComponent.js"));
profile
냐아아아아아아아아앙

0개의 댓글