프리 패칭 (Pre-fetching)

Updated: 2025-05-17

reactnext.js
cover image

React의 전통적인 번들링 방식과 라우팅 구현

React에서는 전통적으로 서버로부터 모든 자바스크립트 파일(JS Bundle)을 한 번에 전달받는 방식으로 작동합니다. 이 접근 방식의 실제 구현과 페이지 라우팅 방법을 살펴보겠습니다.

페이지 라우팅 구현하기

페이지 이동을 위해 react-router-dom 라이브러리를 활용하는 방법을 알아보겠습니다. 이번 예시는 createBrowserRouter를 활용해서 페이지 이동을 구현해보도록 하겠습니다.

router/index.tsx

1import { createBrowserRouter } from "react-router-dom"; 2import AComponent from "../pages/a"; 3import App from "../App"; 4import BComponent from "../pages/b"; 5import CComponent from "../pages/c"; 6 7const router = createBrowserRouter([ 8 { 9 path: "/", 10 element: <App />, 11 }, 12 { 13 path: "/a", 14 element: <AComponent />, 15 }, 16 { 17 path: "/b", 18 element: <BComponent />, 19 }, 20 { 21 path: "/c", 22 element: <CComponent />, 23 }, 24]) 25 26export default router;

main.tsx

1import { StrictMode } from 'react' 2import { createRoot } from 'react-dom/client' 3import './index.css' 4import { RouterProvider } from 'react-router-dom' 5import router from './routes/index.tsx' 6 7createRoot(document.getElementById('root')!).render( 8 <StrictMode> 9 <RouterProvider router={router}/> 10 </StrictMode>, 11)

app.tsx

1import { useEffect, useState } from 'react' 2import './App.css' 3import { Link } from 'react-router-dom'; 4 5interface Element { 6 albumId : number; 7 id : number; 8 title : string; 9 url : string; 10 thumbnailUrl : string; 11} 12 13function App() { 14 const [element , setElement] = useState<Element[]>([]); 15 16 const getData = async () => { 17 const response = await fetch("https://jsonplaceholder.typicode.com/photos"); 18 const result = await response.json(); 19 setElement(result); 20 } 21 22 useEffect(() => { 23 getData(); 24 },[]); 25 26 console.log('element',element); 27 28 return ( 29 <> 30 <div> 31 <h1>CSR TEST</h1> 32 <ul> 33 <li> 34 <Link to={"/a"}>페이지 이동 A</Link> 35 </li> 36 <li> 37 <Link to={"/b"}>페이지 이동 B</Link> 38 </li> 39 <li> 40 <Link to={"/c"}>페이지 이동 C</Link> 41 </li> 42 </ul> 43 <div> 44 {element?.map((el) => { 45 return ( 46 <ul key={el.id}> 47 <li>{el.albumId}</li> 48 <li>{el.title}</li> 49 <li>{el.thumbnailUrl}</li> 50 </ul> 51 ) 52 })} 53 </div> 54 </div> 55 </> 56 ) 57} 58 59export default App 60

페이지 라우팅을 구성한 후, 실제로 페이지 이동 시 발생하는 네트워크 요청을 살펴보겠습니다.

이동 전

image.png

이동 후

image.png

이처럼 리액트는 애플리케이션이 처음 로드될 때 모든 컴포넌트를 포함한 전체 JS 번들이 다운로드됩니다. 사용자가 다른 페이지로 이동하더라도 서버에 추가 요청 없이 클라이언트 측에서 라우팅이 처리됩니다.

React JS Bundle이 가져온 문제와 해결책

React의 기본 동작 방식은 첫 페이지 진입 시 모든 JS Bundle을 다운로드하고, 이후 페이지 전환은 이미 로드된 번들을 활용하는 것입니다. 이 방식은 다음과 같은 문제점을 가지고 있습니다.

  1. 초기 로딩 시간 증가: 애플리케이션이 커질수록 번들 사이즈가 증가하여 초기 로딩 시간이 길어집니다.
  2. 사용자 경험 저하: 불필요한 코드까지 로드하면서 성능이 저하됩니다.
  3. 리소스 낭비: 사용자가 방문하지 않을 페이지의 코드까지 모두 다운로드합니다.

위와 같은 방식을 해결하기 위해서 React에서는 Reac.lazy()와 Suspense를 통해 코드 스플리팅을 진행하여 JS Bundle을 감소시키는 노력을 해왔습니다.

React lazy와 Suspense 활용하기

1import { createBrowserRouter } from 'react-router-dom'; 2import App from '../App'; 3import BComponent from '../pages/b'; 4import CComponent from '../pages/c'; 5import { lazy, Suspense } from 'react'; 6 7const AComponent = lazy(() => import('../pages/a')); 8 9const router = createBrowserRouter([ 10 { 11 path: '/', 12 element: <App />, 13 }, 14 { 15 path: '/a', 16 element: ( 17 <Suspense fallback={<div>Loading!!!</div>}> 18 <AComponent />, 19 </Suspense> 20 ), 21 }, 22 { 23 path: '/b', 24 element: <BComponent />, 25 }, 26 { 27 path: '/c', 28 element: <CComponent />, 29 }, 30]); 31 32export default router; 33

사용방법은 간단합니다. 우리가 위에서 만든 routes 파일에서 import문을 lazy를 활용하여 가져온 후 element property를 suspense를 활용하여 감싸주면 됩니다.

그럼 아래와 같이 필요한 페이지의 JS Bundle을 가져올 수 있게 됩니다.

image.png

Next.js의 코드 스플리팅과 번들 최적화 전략

nextjs에서는 위와 같은 문제점을 해결하기 위해서 요청하는 페이지의 JS Bundle만 가져오게 내부적으로 코드 스플리팅을 제공했고 아래와 같이 페이지 이동시 필요한 JS만 가져오게 변경되었습니다.

image.png

아래 예제를 통해서 살펴보겠습니다.

code-splitting.tsx

1import { useRouter } from "next/router" 2 3export default function CodeSplitting(){ 4 const router = useRouter(); 5 6 return ( 7 <ul> 8 <li onClick={() => router.push("/data-fetching/csr")}> 9 CSR 페이지 이동! 10 </li> 11 <li onClick={() => router.push("/data-fetching/ssr")}> 12 SSR 페이지 이동! 13 </li> 14 <li onClick={() => router.push("/data-fetching/ssg")}> 15 SSG 페이지 이동! 16 </li> 17 <li onClick={() => router.push("/data-fetching/isr")}> 18 ISR 페이지 이동! 19 </li> 20 </ul> 21 ) 22}

이동 전

image.png

이동 후

image.png

페이지 이동 시 Network 탭을 확인하면 아래와 같습니다.

  • 처음 방문한 페이지의 JS 번들만 로드됨
  • 다른 페이지로 이동할 때 해당 페이지에 필요한 JS 번들만 추가로 로드됨

Next.js Prefetching

Next.js는 페이지 전환을 매우 빠르게 만들기 위해 Prefetching이라는 강력한 최적화 기능을 제공합니다. 이 기능은 사용자 경험을 크게 향상시키는 핵심 요소입니다.

특징

  • 빠른 페이지 이동: 사용자 경험을 향상시키기 위해 Next.js가 제공하는 최적화 기능입니다.
  • 사전 로딩: 현재 페이지에서 이동 가능한 다른 페이지들의 JavaScript 코드를 백그라운드에서 미리 로드합니다.
  • 프로덕션 환경 전용: 개발 모드에서는 작동하지 않으며, 실제 성능을 확인하려면 npm run buildnpm run start를 통해 프로덕션 빌드를 실행해야 합니다.
  • Link 컴포넌트 필수: 자동 Prefetching은 Next.js의 <Link> 컴포넌트를 사용할 때만 작동합니다. 일반 <a> 태그나 프로그래매틱 라우팅으로는 Prefetching이 발생하지 않습니다.
1import Link from "next/link"; 2 3export default function PreFetching(){ 4 return ( 5 <ul> 6 <li> 7 <Link href={"/data-fetching/csr"}>CSR 페이지 이동!</Link> 8 </li> 9 <li> 10 <Link href={"/data-fetching/ssr"}>SSR 페이지 이동!</Link> 11 </li> 12 <li> 13 <Link href={"/data-fetching/ssg"}>SSG 페이지 이동!</Link> 14 </li> 15 <li> 16 <Link href={"/data-fetching/isr"}>ISR 페이지 이동!</Link> 17 </li> 18 </ul> 19 ) 20}

만약에 위와 같은 기능을 제공하고 싶지 않다면 Link 태그에 prefetch option이 default가 true이기 때문에 false를 적용하면 된다.

📌 참고

https://react.dev/reference/react/lazy

https://react.dev/learn/build-a-react-app-from-scratch#code-splitting

문의 사항이 있으시면 언제든지 개인 메일로 연락 주시기 바랍니다.

메일 보내기

© 2024. kimyoungho all rights reserved.