[React] 코드 스플리팅

10038 단어 ReactReact

react 스터디에서 리액트를 다루는 기술이라는 책을 선정했고 이 책을 읽고 배운 것을 바탕으로 작성되었다.


📌 코드 스플리팅이란?

  • 말 그대로 코드를 분리하는 것을 말한다.
  • 웹팩에서 별도의 설정을 하지 않으면 프로젝트에서 사용 중인 모든 자바스크립트 파일이 하나의 파일(main)로 합져진다.
  • 애플리케이션의 규모가 커질수록 main 파일 크기도 커지는데 그러면 페이지 로딩 시 지금 당장 필요하지 않은 코드도 전부 불러와 페이지 로딩 시간이 길어져 사용자 경험도 안 좋아지고 트래픽도 증가한다.
  • code spliting을 적용하면 당장 필요하지 않은 코드는 분리시켜 나중에 필요할때 불러와서 사용할 수 있다. (코드 비동기 로딩) 그러면 페이지 로딩 시간이 개선된다.

✨ 함수 코드 스플리팅

❗ dynamic import

// notify.js
export default function notify(){
    alert("안녕하세요!");
}
// App.js
// import notify from "./notify";

function App(){
    const onClick = () => {
        import("./notify").then(result => result.default());
        // notify();
    }
    return (
        <button onClick={onClick}>Notify</button>
    );
}
  • 상단에 import를 통해 nofity를 불러오면 notify 코드가 main 파일 안에 들어가게 된다.
  • 하지만 import() 구문을 사용하면 코드를 필요한 시점에 불러와 사용할 수 있고 코드도 따로 파일을 분리시켜 저장된다.
    • chunk 파일: 코드 스플리팅 시 생성되는 자바스크립트 파일
  • import() 구문은 프로미스 객체를 반환하는데 프로미스 객체의 반환값은 불러온 모듈이다.

✨ 컴포넌트 코드 스플리팅

❗ state 이용

  • import()를 통해 컴포넌트를 필요한 시점에 불러와 컴포넌트 자체를 state에 넣는다.
// SplitMe.js
const SplitMe = () => {
    return <div>SplitMe</div>;
}

export default SplitMe;
// App.js
import { Component } from "react";

class App extends Component{
    state = {
        SplitMe: null
    };
    
    handleClick = async () => {
        const loadingModule = await import("./SplitMe");
        this.setState({
            SplitMe: loadingModule.default
        });
    }
    
    
    
    render() {
        const { SplitMe } = this.state;
        return (
            <div>
                <button onClick={handleClick}>Click!</button>
                {SplitMe && <SplitMe/>
            </div>
        );
    }
}

❗ React.lazy와 Suspense

React.lazy()

  • 컴포넌트를 렌더링하는 시점에서 비동기적으로 로딩할 수 있게 해주는 함수
  • import() 구문을 반환하는 콜백함수를 인자로 갖는다.
  • 이때 import() 구문으로 불러와지는 모듈은 React Component를 포함하며 default export를 가져야 한다.
  • 불러온 컴포넌트를 반환한다.
const SplitMe = React.lazy(() => import("./SplitMe"));

Suspense

  • React.lazy로 불러온 컴포넌트는 Suspense 컴포넌트 하위에서 렌더링되어야 한다.
  • fallback prop로 컴포넌트가 로드되길 기다리는 동안 렌더링하려는 React element를 설정할 수 있다.
// App.js
import { useState, Suspense } from "react";

const SplitMe = React.lazy(() => import("./SplitMe"));

function App(){
    const [visible, setVisible] = useState(false);
    const onClick = () => {
        setVisible(true);
    };
    return (
        <div>
            <button onClick={handleClick}>Click!</button>
            <SusPense fallback={<div>loading...</div>}>
                {visible && <SplitMe/>}
            </Suspense>
        </div>
    );

}

❗ Loadable Components

  • 코드 스플리팅을 편하게 하도록 도와주는 서드파티 라이브러리이다.
  • 이 라이브러리의 이점은 서버 사이드 렌더링을 지원한다. (React.lazy와 Suspense는 아직 서버 사이드 렌더링을 지원하지 않는다.)
 const SplitMe = loadable(() => import("./SplitMe"), {
     fallback: <div>loading...</div>
 });
 
 SplitMe.preload(); // 미리 불러오기

✨ 리액트 라우터와 함께 사용하기

import { BrowserRouter as Router, Route, Routes } from 'react-router-dom';
import loadable from "@loadable/component";

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

const App = () => (
  <Router>
    <Suspense fallback={<div>Loading...</div>}>
      <Routes>
        <Route path="/" element={<Home/>}/>
        <Route path="/about" element={<About/>}/>
      </Routes>
    </Suspense>
  </Router>
);
  • 여러 컴포넌트들로 구성된 규모가 큰 SPA를 개발한다고 했을 때 코드 스플리팅을 하지 않으면 자바스크립트 main 파일이 커지게 되고 페이지 로딩 시 아직 필요하지 않은 컴포넌트까지 불러오기 때문에 페이지 로딩 시간이 길어지고 트래픽도 증가하게 된다.
  • 그래서 코드 스플리팅을 통해 당장 필요하지 않는 컴포넌트들을 분리시키고 나중에 컴포넌트가 렌더링되는 시점에 불러올 수 있어 페이지 로딩 시간을 개선할 수 있다.

좋은 웹페이지 즐겨찾기