๋ฆฌ์กํธ ์์คํ์ค ์ํฐํด์ ์๋ณํ๊ณ ์ ๊ฑฐํ๋ ๋ฒ์ ์์๋ณด์ธ์. ๋ณ๋ ฌ ํ์นญ, Render-as-You-Fetch ๋ฑ ๋ ๋น ๋ฅธ ๊ธ๋ก๋ฒ ์ฑ์ ์ํ ๊ณ ๊ธ ์ต์ ํ ์ ๋ต์ ๋ค๋ฃน๋๋ค.
๋ฆฌ์กํธ ์์คํ์ค ์ํฐํด: ์์ฐจ์ ๋ฐ์ดํฐ ๋ก๋ฉ ์ต์ ํ ์ฌ์ธต ๋ถ์
๋งค๋๋ฌ์ด ์ฌ์ฉ์ ๊ฒฝํ์ ์ํ ๋์์๋ ์ถ๊ตฌ ์์์, ํ๋ก ํธ์๋ ๊ฐ๋ฐ์๋ค์ ์ง์ฐ ์๊ฐ์ด๋ผ๋ ๊ฐ๋ ฅํ ์ ๊ณผ ๋์์์ด ์ธ์ฐ๊ณ ์์ต๋๋ค. ์ ์ธ๊ณ ์ฌ์ฉ์๋ค์๊ฒ๋ ๋งค ๋ฐ๋ฆฌ์ด๊ฐ ์ค์ํฉ๋๋ค. ๋๋ฆฌ๊ฒ ๋ก๋ฉ๋๋ ์ ํ๋ฆฌ์ผ์ด์ ์ ์ฌ์ฉ์๋ฅผ ์ข์ ์ํฌ ๋ฟ๋ง ์๋๋ผ, ์ฐธ์ฌ๋, ์ ํ์จ, ๊ทธ๋ฆฌ๊ณ ํ์ฌ์ ์์ต์ ์ง์ ์ ์ธ ์ํฅ์ ๋ฏธ์น ์ ์์ต๋๋ค. ๋ฆฌ์กํธ๋ ์ปดํฌ๋ํธ ๊ธฐ๋ฐ ์ํคํ ์ฒ์ ์ํ๊ณ๋ฅผ ํตํด ๋ณต์กํ UI๋ฅผ ๊ตฌ์ถํ ์ ์๋ ๊ฐ๋ ฅํ ๋๊ตฌ๋ฅผ ์ ๊ณตํด์์ผ๋ฉฐ, ๊ทธ์ค ๊ฐ์ฅ ํ์ ์ ์ธ ๊ธฐ๋ฅ ์ค ํ๋๋ ๋ฆฌ์กํธ ์์คํ์ค(React Suspense)์ ๋๋ค.
์์คํ์ค๋ ๋น๋๊ธฐ ์์ ์ ์ฒ๋ฆฌํ๋ ์ ์ธ์ ์ธ ๋ฐฉ๋ฒ์ ์ ๊ณตํ์ฌ, ์ปดํฌ๋ํธ ํธ๋ฆฌ ๋ด์์ ์ง์ ๋ก๋ฉ ์ํ๋ฅผ ์ง์ ํ ์ ์๊ฒ ํด์ค๋๋ค. ์ด๋ ๋ฐ์ดํฐ ํ์นญ, ์ฝ๋ ๋ถํ ๋ฐ ๊ธฐํ ๋น๋๊ธฐ ์์ ์ ๋ํ ์ฝ๋๋ฅผ ๋จ์ํํฉ๋๋ค. ๊ทธ๋ฌ๋ ์ด ๊ฐ๋ ฅํ ๊ธฐ๋ฅ์๋ ์๋ก์ด ์ฑ๋ฅ ๊ณ ๋ ค ์ฌํญ์ด ๋ฐ๋ฆ ๋๋ค. ๋ฐ์ํ ์ ์๋ ํํ๋ฉด์๋ ๋ฏธ๋ฌํ ์ฑ๋ฅ ํจ์ ์ ๋ฐ๋ก "์์คํ์ค ์ํฐํด"์ ๋๋ค. ์ด๋ ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ก๋ ์๊ฐ์ ์ฌ๊ฐํ๊ฒ ์ ํ์ํฌ ์ ์๋ ์์ฐจ์ ์ธ ๋ฐ์ดํฐ ๋ก๋ฉ ์์ ์ ์ฐ์์ ๋๋ค.
์ด ์ข ํฉ ๊ฐ์ด๋๋ ์ ์ธ๊ณ ๋ฆฌ์กํธ ๊ฐ๋ฐ์๋ค์ ์ํด ์ค๊ณ๋์์ต๋๋ค. ์ฐ๋ฆฌ๋ ์์คํ์ค ์ํฐํด ํ์์ ํด๋ถํ๊ณ , ์ด๋ฅผ ์๋ณํ๋ ๋ฐฉ๋ฒ์ ํ๊ตฌํ๋ฉฐ, ์ด๋ฅผ ์ ๊ฑฐํ๊ธฐ ์ํ ๊ฐ๋ ฅํ ์ ๋ต๋ค์ ์์ธํ ๋ถ์ํ ๊ฒ์ ๋๋ค. ์ด ๊ธ์ ๋ค ์ฝ๊ณ ๋๋ฉด, ์ฌ๋ฌ๋ถ์ ์ ํ๋ฆฌ์ผ์ด์ ์ ๋๋ฆฌ๊ณ ์์กด์ ์ธ ์์ฒญ์ ์ฐ์์์ ๊ณ ๋๋ก ์ต์ ํ๋ ๋ณ๋ ฌ ๋ฐ์ดํฐ ํ์นญ ๋จธ์ ์ผ๋ก ๋ณํํ์ฌ, ๋ชจ๋ ๊ณณ์ ์ฌ์ฉ์๋ค์๊ฒ ์ฐ์ํ ๊ฒฝํ์ ์ ๊ณตํ ์ ์๊ฒ ๋ ๊ฒ์ ๋๋ค.
React Suspense ์ดํดํ๊ธฐ: ๊ฐ๋จํ ๋ณต์ต
๋ฌธ์ ์ ๊น์ด ๋ค์ด๊ฐ๊ธฐ ์ ์, ๋ฆฌ์กํธ ์์คํ์ค์ ํต์ฌ ๊ฐ๋ ์ ๊ฐ๋จํ ๋ณต์ตํด ๋ณด๊ฒ ์ต๋๋ค. ํต์ฌ์ ์ผ๋ก, ์์คํ์ค๋ ์ปดํฌ๋ํธ๊ฐ ๋ ๋๋ง๋๊ธฐ ์ ์ ๋ฌด์ธ๊ฐ๋ฅผ "๊ธฐ๋ค๋ฆฌ๊ฒ" ํ ์ ์๊ฒ ํด์ฃผ๋ฉฐ, ์ด๋ ๋ณต์กํ ์กฐ๊ฑด๋ถ ๋ก์ง(์: `if (isLoading) { ... }`)์ ์์ฑํ ํ์๊ฐ ์์ต๋๋ค.
์์คํ์ค ๊ฒฝ๊ณ ๋ด์ ์ปดํฌ๋ํธ๊ฐ ์ผ์ ์ค๋จ๋๋ฉด(ํ๋ก๋ฏธ์ค๋ฅผ ๋์ ธ์), ๋ฆฌ์กํธ๋ ์ด๋ฅผ ํฌ์ฐฉํ์ฌ ์ง์ ๋ `fallback` UI๋ฅผ ํ์ํฉ๋๋ค. ํ๋ก๋ฏธ์ค๊ฐ ํด๊ฒฐ๋๋ฉด, ๋ฆฌ์กํธ๋ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ง๊ณ ์ปดํฌ๋ํธ๋ฅผ ๋ค์ ๋ ๋๋งํฉ๋๋ค.
๋ฐ์ดํฐ ํ์นญ์ ์ฌ์ฉํ ๊ฐ๋จํ ์์๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค:
- // api.js - fetch ํธ์ถ์ ๋ํํ๋ ์ ํธ๋ฆฌํฐ
- const cache = new Map();
- export function fetchData(url) {
- if (!cache.has(url)) {
- cache.set(url, getData(url));
- }
- return cache.get(url);
- }
- async function getData(url) {
- const res = await fetch(url);
- if (res.ok) {
- return res.json();
- } else {
- throw new Error('Failed to fetch');
- }
- }
๊ทธ๋ฆฌ๊ณ ์ฌ๊ธฐ ์์คํ์ค์ ํธํ๋๋ ํ ์ ์ฌ์ฉํ๋ ์ปดํฌ๋ํธ๊ฐ ์์ต๋๋ค:
- // useData.js - ํ๋ก๋ฏธ์ค๋ฅผ ๋์ง๋ ํ
- import { fetchData } from './api';
- function useData(url) {
- const data = fetchData(url);
- if (data instanceof Promise) {
- throw data; // ์ด๊ฒ์ด Suspense๋ฅผ ํธ๋ฆฌ๊ฑฐํฉ๋๋ค
- }
- return data;
- }
๋ง์ง๋ง์ผ๋ก, ์ปดํฌ๋ํธ ํธ๋ฆฌ์ ๋๋ค:
- // MyComponent.js
- import React, { Suspense } from 'react';
- import { useData } from './useData';
- function UserProfile() {
- const user = useData('/api/user/123');
- return <h1>ํ์ํฉ๋๋ค, {user.name}๋</h1>;
- }
- function App() {
- return (
- <Suspense fallback={<h2>์ฌ์ฉ์ ํ๋กํ ๋ก๋ฉ ์ค...</h2>}>
- <UserProfile />
- </Suspense>
- );
- }
์ด๊ฒ์ ๋จ์ผ ๋ฐ์ดํฐ ์์กด์ฑ์ ๋ํด ํ๋ฅญํ๊ฒ ์๋ํฉ๋๋ค. ๋ฌธ์ ๋ ์ฌ๋ฌ ๊ฐ์ ์ค์ฒฉ๋ ๋ฐ์ดํฐ ์์กด์ฑ์ด ์์ ๋ ๋ฐ์ํฉ๋๋ค.
"์ํฐํด"์ด๋ ๋ฌด์์ธ๊ฐ? ์ฑ๋ฅ ๋ณ๋ชฉ ํ์ ํํค์น๊ธฐ
์น ๊ฐ๋ฐ์ ๋งฅ๋ฝ์์, ์ํฐํด(waterfall)์ ์์๋๋ก, ํ๋์ฉ ์คํ๋์ด์ผ ํ๋ ๋คํธ์ํฌ ์์ฒญ์ ์ฐ์์ ์๋ฏธํฉ๋๋ค. ์ฒด์ธ์ ๊ฐ ์์ฒญ์ ์ด์ ์์ฒญ์ด ์ฑ๊ณต์ ์ผ๋ก ์๋ฃ๋ ํ์๋ง ์์๋ ์ ์์ต๋๋ค. ์ด๋ ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ก๋ฉ ์๊ฐ์ ํฌ๊ฒ ๋ฆ์ถ ์ ์๋ ์์กด์ฑ ์ฒด์ธ์ ๋ง๋ญ๋๋ค.
๋ ์คํ ๋์์ ์ธ ์ฝ์ค ์๋ฆฌ๋ฅผ ์ฃผ๋ฌธํ๋ค๊ณ ์์ํด ๋ณด์ธ์. ์ํฐํด ์ ๊ทผ ๋ฐฉ์์ ์ ํผํ์ด์ ๋ฅผ ์ฃผ๋ฌธํ๊ณ , ๊ทธ๊ฒ์ด ๋์ฐฉํด์ ๋ค ๋จน๊ธฐ๋ฅผ ๊ธฐ๋ค๋ฆฐ ๋ค์, ๋ฉ์ธ ์ฝ์ค๋ฅผ ์ฃผ๋ฌธํ๊ณ , ๊ทธ๊ฒ์ ๊ธฐ๋ค๋ ค์ ๋ค ๋จน๊ณ , ๊ทธ๋ฐ ๋ค์์์ผ ๋์ ํธ๋ฅผ ์ฃผ๋ฌธํ๋ ๊ฒ์ ๋๋ค. ์ด ๋๊ธฐ ์๊ฐ์ ๋ชจ๋ ๊ฐ๋ณ ๋๊ธฐ ์๊ฐ์ ํฉ์ ๋๋ค. ํจ์ฌ ๋ ํจ์จ์ ์ธ ์ ๊ทผ ๋ฐฉ์์ ์ธ ์ฝ์ค ๋ชจ๋๋ฅผ ํ ๋ฒ์ ์ฃผ๋ฌธํ๋ ๊ฒ์ ๋๋ค. ๊ทธ๋ฌ๋ฉด ์ฃผ๋ฐฉ์์ ๋ณ๋ ฌ๋ก ์ค๋นํ ์ ์์ด ์ด ๋๊ธฐ ์๊ฐ์ ๋ํญ ์ค์ผ ์ ์์ต๋๋ค.
๋ฆฌ์กํธ ์์คํ์ค ์ํฐํด์ ์ด ๋นํจ์จ์ ์ธ ์์ฐจ ํจํด์ ๋ฆฌ์กํธ ์ปดํฌ๋ํธ ํธ๋ฆฌ ๋ด์ ๋ฐ์ดํฐ ํ์นญ์ ์ ์ฉํ๋ ๊ฒ์ ๋๋ค. ์ด๋ ์ผ๋ฐ์ ์ผ๋ก ๋ถ๋ชจ ์ปดํฌ๋ํธ๊ฐ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์จ ๋ค์ ์์ ์ปดํฌ๋ํธ๋ฅผ ๋ ๋๋งํ๊ณ , ๊ทธ ์์ ์ปดํฌ๋ํธ๊ฐ ๋ถ๋ชจ๋ก๋ถํฐ ๋ฐ์ ๊ฐ์ ์ฌ์ฉํ์ฌ ์์ฒด ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ฌ ๋ ๋ฐ์ํฉ๋๋ค.
์ ํ์ ์ธ ์ํฐํด ์์
์ด์ ์์๋ฅผ ํ์ฅํด ๋ณด๊ฒ ์ต๋๋ค. ์ฌ์ฉ์ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ค๋ `ProfilePage`๊ฐ ์์ต๋๋ค. ์ฌ์ฉ์ ๋ฐ์ดํฐ๋ฅผ ๋ฐ์ ํ์๋ `UserPosts` ์ปดํฌ๋ํธ๋ฅผ ๋ ๋๋งํ๊ณ , ์ด ์ปดํฌ๋ํธ๋ ์ฌ์ฉ์์ ID๋ฅผ ์ฌ์ฉํ์ฌ ํด๋น ์ฌ์ฉ์์ ๊ฒ์๋ฌผ์ ๊ฐ์ ธ์ต๋๋ค.
- // ์ด์ : ๋ช ํํ ์ํฐํด ๊ตฌ์กฐ
- function ProfilePage({ userId }) {
- // 1. ์ฒซ ๋ฒ์งธ ๋คํธ์ํฌ ์์ฒญ์ด ์ฌ๊ธฐ์ ์์๋ฉ๋๋ค
- const user = useUserData(userId); // ์ปดํฌ๋ํธ๊ฐ ์ฌ๊ธฐ์ ์ผ์ ์ค๋จ๋ฉ๋๋ค
- return (
- <div>
- <h1>{user.name}</h1>
- <p>{user.bio}</p>
- <Suspense fallback={<h3>๊ฒ์๋ฌผ ๋ก๋ฉ ์ค...</h3>}>
- // ์ด ์ปดํฌ๋ํธ๋ `user`๊ฐ ์ฌ์ฉ ๊ฐ๋ฅํด์ง ๋๊น์ง ๋ง์ดํธ๋์ง๋ ์์ต๋๋ค
- <UserPosts userId={user.id} />
- </Suspense>
- </div>
- );
- }
- function UserPosts({ userId }) {
- // 2. ๋ ๋ฒ์งธ ๋คํธ์ํฌ ์์ฒญ์ ์ฒซ ๋ฒ์งธ ์์ฒญ์ด ์๋ฃ๋ ํ์์ผ ์ฌ๊ธฐ์ ์์๋ฉ๋๋ค
- const posts = useUserPosts(userId); // ์ปดํฌ๋ํธ๊ฐ ๋ค์ ์ผ์ ์ค๋จ๋ฉ๋๋ค
- return (
- <ul>
- {posts.map(post => (<li key={post.id}>{post.title}</li>))}
- </ul>
- );
- }
์ด๋ฒคํธ ์์๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค:
- `ProfilePage`๊ฐ ๋ ๋๋ง๋๊ณ `useUserData(userId)`๋ฅผ ํธ์ถํฉ๋๋ค.
- ์ ํ๋ฆฌ์ผ์ด์ ์ด ์ผ์ ์ค๋จ๋๊ณ , fallback UI๋ฅผ ๋ณด์ฌ์ค๋๋ค. ์ฌ์ฉ์ ๋ฐ์ดํฐ์ ๋ํ ๋คํธ์ํฌ ์์ฒญ์ด ์งํ ์ค์ ๋๋ค.
- ์ฌ์ฉ์ ๋ฐ์ดํฐ ์์ฒญ์ด ์๋ฃ๋ฉ๋๋ค. ๋ฆฌ์กํธ๊ฐ `ProfilePage`๋ฅผ ๋ค์ ๋ ๋๋งํฉ๋๋ค.
- ์ด์ `user` ๋ฐ์ดํฐ๋ฅผ ์ฌ์ฉํ ์ ์์ผ๋ฏ๋ก, `UserPosts`๊ฐ ์ฒ์์ผ๋ก ๋ ๋๋ง๋ฉ๋๋ค.
- `UserPosts`๊ฐ `useUserPosts(userId)`๋ฅผ ํธ์ถํฉ๋๋ค.
- ์ ํ๋ฆฌ์ผ์ด์ ์ด ๋ค์ ์ผ์ ์ค๋จ๋๊ณ , ๋ด๋ถ์ "๊ฒ์๋ฌผ ๋ก๋ฉ ์ค..." fallback์ ๋ณด์ฌ์ค๋๋ค. ๊ฒ์๋ฌผ์ ๋ํ ๋คํธ์ํฌ ์์ฒญ์ด ์์๋ฉ๋๋ค.
- ๊ฒ์๋ฌผ ๋ฐ์ดํฐ ์์ฒญ์ด ์๋ฃ๋ฉ๋๋ค. ๋ฆฌ์กํธ๊ฐ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ง๊ณ `UserPosts`๋ฅผ ๋ค์ ๋ ๋๋งํฉ๋๋ค.
์ด ๋ก๋ ์๊ฐ์ `์ฌ์ฉ์ ๊ฐ์ ธ์ค๊ธฐ ์๊ฐ + ๊ฒ์๋ฌผ ๊ฐ์ ธ์ค๊ธฐ ์๊ฐ`์ ๋๋ค. ๊ฐ ์์ฒญ์ด 500ms ๊ฑธ๋ฆฐ๋ค๋ฉด, ์ฌ์ฉ์๋ ๊ผฌ๋ฐ 1์ด๋ฅผ ๊ธฐ๋ค๋ฆฝ๋๋ค. ์ด๊ฒ์ด ์ ํ์ ์ธ ์ํฐํด์ด๋ฉฐ, ์ฐ๋ฆฌ๊ฐ ํด๊ฒฐํด์ผ ํ ์ฑ๋ฅ ๋ฌธ์ ์ ๋๋ค.
์ ํ๋ฆฌ์ผ์ด์ ์์ ์์คํ์ค ์ํฐํด ์๋ณํ๊ธฐ
๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ธฐ ์ ์, ๋จผ์ ์ฐพ์์ผ ํฉ๋๋ค. ๋คํํ๋, ์ต์ ๋ธ๋ผ์ฐ์ ์ ๊ฐ๋ฐ ๋๊ตฌ๋ค์ ์ํฐํด์ ๋น๊ต์ ์ฝ๊ฒ ๋ฐ๊ฒฌํ ์ ์๊ฒ ํด์ค๋๋ค.
1. ๋ธ๋ผ์ฐ์ ๊ฐ๋ฐ์ ๋๊ตฌ ์ฌ์ฉํ๊ธฐ
๋ธ๋ผ์ฐ์ ๊ฐ๋ฐ์ ๋๊ตฌ์ ๋คํธ์ํฌ(Network) ํญ์ ์ต๊ณ ์ ์น๊ตฌ์ ๋๋ค. ๋ค์์ ์ฐพ์๋ณด์ธ์:
- ๊ณ๋จ์ ํจํด: ์ํฐํด์ด ์๋ ํ์ด์ง๋ฅผ ๋ก๋ํ๋ฉด ๋คํธ์ํฌ ์์ฒญ ํ์๋ผ์ธ์์ ๋๋ ทํ ๊ณ๋จ์ ๋๋ ๋๊ฐ์ ํจํด์ ๋ณผ ์ ์์ต๋๋ค. ํ ์์ฒญ์ ์์ ์๊ฐ์ด ์ด์ ์์ฒญ์ ์ข ๋ฃ ์๊ฐ๊ณผ ๊ฑฐ์ ์๋ฒฝํ๊ฒ ์ผ์นํฉ๋๋ค.
- ํ์ด๋ฐ ๋ถ์: ๋คํธ์ํฌ ํญ์ "์ํฐํด" ์ด์ ๊ฒ์ฌํ์ธ์. ๊ฐ ์์ฒญ์ ํ์ด๋ฐ(๋๊ธฐ, ์ฝํ ์ธ ๋ค์ด๋ก๋) ๋ถ์์ ๋ณผ ์ ์์ต๋๋ค. ์์ฐจ์ ์ธ ์ฒด์ธ์ ์๊ฐ์ ์ผ๋ก ๋ช ํํ๊ฒ ๋๋ฌ๋ฉ๋๋ค. ์์ฒญ B์ "์์ ์๊ฐ"์ด ์์ฒญ A์ "์ข ๋ฃ ์๊ฐ"๋ณด๋ค ํฌ๋ค๋ฉด, ์ํฐํด์ผ ๊ฐ๋ฅ์ฑ์ด ๋์ต๋๋ค.
2. React ๊ฐ๋ฐ์ ๋๊ตฌ ์ฌ์ฉํ๊ธฐ
React ๊ฐ๋ฐ์ ๋๊ตฌ ํ์ฅ ํ๋ก๊ทธ๋จ์ ๋ฆฌ์กํธ ์ ํ๋ฆฌ์ผ์ด์ ๋๋ฒ๊น ์ ํ์์ ์ ๋๋ค.
- ํ๋กํ์ผ๋ฌ(Profiler): ํ๋กํ์ผ๋ฌ๋ฅผ ์ฌ์ฉํ์ฌ ์ปดํฌ๋ํธ์ ๋ ๋๋ง ์๋ช ์ฃผ๊ธฐ์ ๋ํ ์ฑ๋ฅ ์ถ์ ์ ๊ธฐ๋กํ์ธ์. ์ํฐํด ์๋๋ฆฌ์ค์์๋ ๋ถ๋ชจ ์ปดํฌ๋ํธ๊ฐ ๋ ๋๋ง๋๊ณ , ๋ฐ์ดํฐ๋ฅผ ํด๊ฒฐํ ๋ค์, ๋ฆฌ๋ ๋๋ง์ ํธ๋ฆฌ๊ฑฐํ์ฌ ์์ ์ปดํฌ๋ํธ๊ฐ ๋ง์ดํธ๋๊ณ ์ผ์ ์ค๋จ๋๋ ๊ฒ์ ๋ณผ ์ ์์ต๋๋ค. ์ด๋ฌํ ๋ ๋๋ง๊ณผ ์ผ์ ์ค๋จ์ ์ฐ์์ ๊ฐ๋ ฅํ ์งํ์ ๋๋ค.
- ์ปดํฌ๋ํธ(Components) ํญ: ์ต์ ๋ฒ์ ์ React DevTools๋ ํ์ฌ ์ด๋ค ์ปดํฌ๋ํธ๊ฐ ์ผ์ ์ค๋จ๋์๋์ง ๋ณด์ฌ์ค๋๋ค. ๋ถ๋ชจ ์ปดํฌ๋ํธ๊ฐ ์ผ์ ์ค๋จ ์ํ์์ ํด์ ๋ ์งํ ์์ ์ปดํฌ๋ํธ๊ฐ ์ผ์ ์ค๋จ๋๋ ๊ฒ์ ๊ด์ฐฐํ๋ฉด ์ํฐํด์ ์์ธ์ ์ ํํ ์ฐพ์๋ด๋ ๋ฐ ๋์์ด ๋ ์ ์์ต๋๋ค.
3. ์ ์ ์ฝ๋ ๋ถ์
๋๋ก๋ ์ฝ๋๋ฅผ ์ฝ๋ ๊ฒ๋ง์ผ๋ก๋ ์ ์ฌ์ ์ธ ์ํฐํด์ ์๋ณํ ์ ์์ต๋๋ค. ๋ค์๊ณผ ๊ฐ์ ํจํด์ ์ฐพ์๋ณด์ธ์:
- ์ค์ฒฉ๋ ๋ฐ์ดํฐ ์์กด์ฑ: ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์์ ๊ทธ ๊ฒฐ๊ณผ๋ฅผ ์์ ์ปดํฌ๋ํธ์ prop์ผ๋ก ์ ๋ฌํ๊ณ , ์์ ์ปดํฌ๋ํธ๊ฐ ๊ทธ prop์ ์ฌ์ฉํ์ฌ ๋ ๋ง์ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ค๋ ์ปดํฌ๋ํธ. ์ด๊ฒ์ด ๊ฐ์ฅ ์ผ๋ฐ์ ์ธ ํจํด์ ๋๋ค.
- ์์ฐจ์ ์ธ ํ : ๋จ์ผ ์ปดํฌ๋ํธ ๋ด์์ ํ๋์ ์ปค์คํ ๋ฐ์ดํฐ ํ์นญ ํ ์์ ์ป์ ๋ฐ์ดํฐ๋ฅผ ์ฌ์ฉํ์ฌ ๋ ๋ฒ์งธ ํ ์์ ํธ์ถ์ ํ๋ ๊ฒฝ์ฐ. ์๋ฐํ ๋งํด ๋ถ๋ชจ-์์ ์ํฐํด์ ์๋์ง๋ง, ๋จ์ผ ์ปดํฌ๋ํธ ๋ด์์ ๋์ผํ ์์ฐจ์ ๋ณ๋ชฉ ํ์์ ๋ง๋ญ๋๋ค.
์ํฐํด ์ต์ ํ ๋ฐ ์ ๊ฑฐ ์ ๋ต
์ํฐํด์ ์๋ณํ๋ค๋ฉด, ์ด์ ํด๊ฒฐํ ์ฐจ๋ก์ ๋๋ค. ๋ชจ๋ ์ต์ ํ ์ ๋ต์ ํต์ฌ ์์น์ ์์ฐจ์ ํ์นญ์์ ๋ณ๋ ฌ ํ์นญ์ผ๋ก ์ ํํ๋ ๊ฒ์ ๋๋ค. ์ฐ๋ฆฌ๋ ํ์ํ ๋ชจ๋ ๋คํธ์ํฌ ์์ฒญ์ ๊ฐ๋ฅํ ํ ๋นจ๋ฆฌ, ๊ทธ๋ฆฌ๊ณ ํ ๋ฒ์ ์์ํ๊ธฐ๋ฅผ ์ํฉ๋๋ค.
์ ๋ต 1: `Promise.all`์ ์ด์ฉํ ๋ณ๋ ฌ ๋ฐ์ดํฐ ํ์นญ
์ด๊ฒ์ด ๊ฐ์ฅ ์ง์ ์ ์ธ ์ ๊ทผ ๋ฐฉ์์ ๋๋ค. ํ์ํ ๋ชจ๋ ๋ฐ์ดํฐ๋ฅผ ๋ฏธ๋ฆฌ ์๊ณ ์๋ค๋ฉด, ๋ชจ๋ ์์ฒญ์ ๋์์ ์์ํ๊ณ ๋ชจ๋ ์์ฒญ์ด ์๋ฃ๋ ๋๊น์ง ๊ธฐ๋ค๋ฆด ์ ์์ต๋๋ค.
๊ฐ๋ : ํ์น๋ฅผ ์ค์ฒฉ์ํค๋ ๋์ , ๊ณตํต ๋ถ๋ชจ๋ ์ ํ๋ฆฌ์ผ์ด์ ๋ก์ง์ ์์ ์์ค์์ ํธ๋ฆฌ๊ฑฐํ๊ณ , `Promise.all`๋ก ๊ฐ์ผ ๋ค์, ๋ฐ์ดํฐ๊ฐ ํ์ํ ์ปดํฌ๋ํธ๋ก ์ ๋ฌํฉ๋๋ค.
`ProfilePage` ์์ ๋ฅผ ๋ฆฌํฉํ ๋งํด ๋ณด๊ฒ ์ต๋๋ค. ๋ชจ๋ ๊ฒ์ ๋ณ๋ ฌ๋ก ๊ฐ์ ธ์ค๋ ์๋ก์ด ์ปดํฌ๋ํธ `ProfilePageData`๋ฅผ ๋ง๋ค ์ ์์ต๋๋ค.
- // api.js (fetch ํจ์๋ฅผ ๋ ธ์ถํ๋๋ก ์์ )
- export async function fetchUser(userId) { ... }
- export async function fetchPostsForUser(userId) { ... }
- // ์ด์ : ์ํฐํด
- function ProfilePage({ userId }) {
- const user = useUserData(userId); // ์์ฒญ 1
- return <UserPosts userId={user.id} />; // ์์ฒญ 2๋ ์์ฒญ 1์ด ๋๋ ํ์ ์์
- }
- // ์ดํ: ๋ณ๋ ฌ ํ์นญ
- // ๋ฆฌ์์ค ์์ฑ ์ ํธ๋ฆฌํฐ
- function createProfileData(userId) {
- const userPromise = fetchUser(userId);
- const postsPromise = fetchPostsForUser(userId);
- return {
- user: wrapPromise(userPromise),
- posts: wrapPromise(postsPromise),
- };
- }
- // `wrapPromise`๋ ์ปดํฌ๋ํธ๊ฐ ํ๋ก๋ฏธ์ค ๊ฒฐ๊ณผ๋ฅผ ์ฝ๊ฒ ํด์ฃผ๋ ํฌํผ์ ๋๋ค.
- // ํ๋ก๋ฏธ์ค๊ฐ ๋๊ธฐ ์ค์ด๋ฉด, ํ๋ก๋ฏธ์ค๋ฅผ ๋์ง๋๋ค.
- // ํ๋ก๋ฏธ์ค๊ฐ ํด๊ฒฐ๋๋ฉด, ๊ฐ์ ๋ฐํํฉ๋๋ค.
- // ํ๋ก๋ฏธ์ค๊ฐ ๊ฑฐ๋ถ๋๋ฉด, ์๋ฌ๋ฅผ ๋์ง๋๋ค.
- const resource = createProfileData('123');
- function ProfilePage() {
- const user = resource.user.read(); // ์ฝ๊ฑฐ๋ ์ผ์ ์ค๋จ
- return (
- <div>
- <h1>{user.name}</h1>
- <Suspense fallback={<h3>๊ฒ์๋ฌผ ๋ก๋ฉ ์ค...</h3>}>
- <UserPosts />
- </Suspense>
- </div>
- );
- }
- function UserPosts() {
- const posts = resource.posts.read(); // ์ฝ๊ฑฐ๋ ์ผ์ ์ค๋จ
- return <ul>...</ul>;
- }
์ด ์์ ๋ ํจํด์์ `createProfileData`๋ ํ ๋ฒ ํธ์ถ๋ฉ๋๋ค. ์ด๊ฒ์ ์ฆ์ ์ฌ์ฉ์ ๋ฐ ๊ฒ์๋ฌผ ๊ฐ์ ธ์ค๊ธฐ ์์ฒญ์ ๋ ๋ค ์์ํฉ๋๋ค. ์ด ๋ก๋ฉ ์๊ฐ์ ์ด์ ๋ ์์ฒญ์ ํฉ์ด ์๋๋ผ ๊ทธ์ค ๊ฐ์ฅ ๋๋ฆฐ ์์ฒญ์ ์ํด ๊ฒฐ์ ๋ฉ๋๋ค. ๋ ๋ค 500ms๊ฐ ๊ฑธ๋ฆฐ๋ค๋ฉด, ์ด ๋๊ธฐ ์๊ฐ์ 1000ms ๋์ ์ฝ 500ms๊ฐ ๋ฉ๋๋ค. ์ด๊ฒ์ ์์ฒญ๋ ๊ฐ์ ์ ๋๋ค.
์ ๋ต 2: ๊ณตํต ์กฐ์์ผ๋ก ๋ฐ์ดํฐ ํ์นญ ๋์ด์ฌ๋ฆฌ๊ธฐ
์ด ์ ๋ต์ ์ฒซ ๋ฒ์งธ ์ ๋ต์ ๋ณํ์ ๋๋ค. ํนํ ๋ ๋ฆฝ์ ์ผ๋ก ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ค๋ ํ์ ์ปดํฌ๋ํธ๊ฐ ์๊ณ , ์ด๋ค์ด ์์ฐจ์ ์ผ๋ก ๋ ๋๋ง๋ ๊ฒฝ์ฐ ๊ทธ๋ค ์ฌ์ด์ ์ํฐํด์ ์ ๋ฐํ ์ ์์ ๋ ์ ์ฉํฉ๋๋ค.
๊ฐ๋ : ๋ฐ์ดํฐ๊ฐ ํ์ํ ๋ชจ๋ ์ปดํฌ๋ํธ์ ๊ณตํต ๋ถ๋ชจ ์ปดํฌ๋ํธ๋ฅผ ์๋ณํฉ๋๋ค. ๋ฐ์ดํฐ ํ์นญ ๋ก์ง์ ๊ทธ ๋ถ๋ชจ๋ก ์ฎ๊น๋๋ค. ๊ทธ๋ฌ๋ฉด ๋ถ๋ชจ๋ ํ์น๋ฅผ ๋ณ๋ ฌ๋ก ์คํํ๊ณ ๋ฐ์ดํฐ๋ฅผ props๋ก ์ ๋ฌํ ์ ์์ต๋๋ค. ์ด๋ ๋ฐ์ดํฐ ํ์นญ ๋ก์ง์ ์ค์ ์ง์คํํ๊ณ ๊ฐ๋ฅํ ํ ๋นจ๋ฆฌ ์คํ๋๋๋ก ๋ณด์ฅํฉ๋๋ค.
- // ์ด์ : ๋ ๋ฆฝ์ ์ผ๋ก ํ์นญํ๋ ํ์ ์ปดํฌ๋ํธ
- function Dashboard() {
- return (
- <div>
- <Suspense fallback={...}><UserInfo /></Suspense>
- <Suspense fallback={...}><Notifications /></Suspense>
- </div>
- );
- }
- // UserInfo๋ ์ฌ์ฉ์ ๋ฐ์ดํฐ๋ฅผ, Notifications๋ ์๋ฆผ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ต๋๋ค.
- // ๋ฆฌ์กํธ๋ ์ด๋ค์ ์์ฐจ์ ์ผ๋ก ๋ ๋๋งํ์ฌ ์์ ์ํฐํด์ ์ ๋ฐํ ์ ์์ต๋๋ค.
- // ์ดํ: ๋ถ๋ชจ๊ฐ ๋ชจ๋ ๋ฐ์ดํฐ๋ฅผ ๋ณ๋ ฌ๋ก ํ์นญ
- const dashboardResource = createDashboardResource();
- function Dashboard() {
- // ์ด ์ปดํฌ๋ํธ๋ ํ์นญํ์ง ์๊ณ , ๋จ์ง ๋ ๋๋ง์ ์กฐ์ ํฉ๋๋ค.
- return (
- <div>
- <Suspense fallback={...}>
- <UserInfo resource={dashboardResource} />
- <Notifications resource={dashboardResource} />
- </Suspense>
- </div>
- );
- }
- function UserInfo({ resource }) {
- const user = resource.user.read();
- return <div>ํ์ํฉ๋๋ค, {user.name}๋</div>;
- }
- function Notifications({ resource }) {
- const notifications = resource.notifications.read();
- return <div>{notifications.length}๊ฐ์ ์๋ก์ด ์๋ฆผ์ด ์์ต๋๋ค.</div>;
- }
ํ์นญ ๋ก์ง์ ๋์ด์ฌ๋ฆผ์ผ๋ก์จ, ์ฐ๋ฆฌ๋ ๋ณ๋ ฌ ์คํ์ ๋ณด์ฅํ๊ณ ์ ์ฒด ๋์๋ณด๋์ ๋ํด ๋จ์ผํ๊ณ ์ผ๊ด๋ ๋ก๋ฉ ๊ฒฝํ์ ์ ๊ณตํฉ๋๋ค.
์ ๋ต 3: ์บ์๊ฐ ์๋ ๋ฐ์ดํฐ ํ์นญ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ฌ์ฉํ๊ธฐ
ํ๋ก๋ฏธ์ค๋ฅผ ์๋์ผ๋ก ์กฐ์ ํ๋ ๊ฒ์ ํจ๊ณผ๊ฐ ์์ง๋ง, ๋๊ท๋ชจ ์ ํ๋ฆฌ์ผ์ด์ ์์๋ ๋ฒ๊ฑฐ๋ก์์ง ์ ์์ต๋๋ค. ๋ฐ๋ก ์ด ์ง์ ์์ ๋ฆฌ์กํธ ์ฟผ๋ฆฌ(ํ์ฌ TanStack Query), SWR, ๋๋ Relay์ ๊ฐ์ ์ ์ฉ ๋ฐ์ดํฐ ํ์นญ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐ ๋น์ ๋ฐํฉ๋๋ค. ์ด ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ค์ ์ํฐํด๊ณผ ๊ฐ์ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด ํน๋ณํ ์ค๊ณ๋์์ต๋๋ค.
๊ฐ๋ : ์ด ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ค์ ์ ์ญ ๋๋ ํ๋ก๋ฐ์ด๋ ์์ค์ ์บ์๋ฅผ ์ ์งํฉ๋๋ค. ์ปดํฌ๋ํธ๊ฐ ๋ฐ์ดํฐ๋ฅผ ์์ฒญํ๋ฉด, ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ ๋จผ์ ์บ์๋ฅผ ํ์ธํฉ๋๋ค. ์ฌ๋ฌ ์ปดํฌ๋ํธ๊ฐ ๋์์ ๋์ผํ ๋ฐ์ดํฐ๋ฅผ ์์ฒญํ๋ฉด, ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ ์์ฒญ์ ์ค๋ณต ์ ๊ฑฐํ์ฌ ์ค์ ๋คํธ์ํฌ ์์ฒญ์ ํ ๋ฒ๋ง ๋ณด๋ผ ๋งํผ ๋๋ํฉ๋๋ค.
๋์์ด ๋๋ ์ :
- ์์ฒญ ์ค๋ณต ์ ๊ฑฐ: ๋ง์ฝ `ProfilePage`์ `UserPosts`๊ฐ ๋ชจ๋ ๋์ผํ ์ฌ์ฉ์ ๋ฐ์ดํฐ๋ฅผ ์์ฒญํ๋ค๋ฉด(์: `useQuery(['user', userId])`), ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ ๋คํธ์ํฌ ์์ฒญ์ ํ ๋ฒ๋ง ์คํํฉ๋๋ค.
- ์บ์ฑ: ๋ฐ์ดํฐ๊ฐ ์ด์ ์์ฒญ์ผ๋ก ์ธํด ์ด๋ฏธ ์บ์์ ์๋ค๋ฉด, ํ์ ์์ฒญ์ ์ฆ์ ํด๊ฒฐ๋์ด ์ ์ฌ์ ์ธ ์ํฐํด์ ์ฐจ๋จํ ์ ์์ต๋๋ค.
- ๊ธฐ๋ณธ์ ์ผ๋ก ๋ณ๋ ฌ: ํ ๊ธฐ๋ฐ์ ํน์ฑ์ ์ปดํฌ๋ํธ์ ์ต์์ ๋ ๋ฒจ์์ `useQuery`๋ฅผ ํธ์ถํ๋๋ก ๊ถ์ฅํฉ๋๋ค. ๋ฆฌ์กํธ๊ฐ ๋ ๋๋ง๋ ๋, ์ด๋ฌํ ๋ชจ๋ ํ ๋ค์ ๊ฑฐ์ ๋์์ ํธ๋ฆฌ๊ฑฐํ์ฌ ๊ธฐ๋ณธ์ ์ผ๋ก ๋ณ๋ ฌ ํ์น๋ฅผ ์ ๋ํฉ๋๋ค.
- // ๋ฆฌ์กํธ ์ฟผ๋ฆฌ ์์
- function ProfilePage({ userId }) {
- // ์ด ํ ์ ๋ ๋๋ง๋์๋ง์ ์ฆ์ ์์ฒญ์ ๋ณด๋ ๋๋ค
- const { data: user } = useQuery(['user', userId], () => fetchUser(userId), { suspense: true });
- return (
- <div>
- <h1>{user.name}</h1>
- <Suspense fallback={<h3>๊ฒ์๋ฌผ ๋ก๋ฉ ์ค...</h3>}>
- // ๋น๋ก ์ด๊ฒ์ด ์ค์ฒฉ๋์ด ์๋๋ผ๋, ๋ฆฌ์กํธ ์ฟผ๋ฆฌ๋ ์ข ์ข ํ์น๋ฅผ ํจ์จ์ ์ผ๋ก ๋ฏธ๋ฆฌ ๊ฐ์ ธ์ค๊ฑฐ๋ ๋ณ๋ ฌํํฉ๋๋ค
- <UserPosts userId={user.id} />
- </Suspense>
- </div>
- );
- }
- function UserPosts({ userId }) {
- const { data: posts } = useQuery(['posts', userId], () => fetchPostsForUser(userId), { suspense: true });
- return <ul>...</ul>;
- }
์ฝ๋ ๊ตฌ์กฐ๊ฐ ์ฌ์ ํ ์ํฐํด์ฒ๋ผ ๋ณด์ผ ์ ์์ง๋ง, ๋ฆฌ์กํธ ์ฟผ๋ฆฌ์ ๊ฐ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ค์ ์ข ์ข ์ด๋ฅผ ์ํํ ๋งํผ ์ถฉ๋ถํ ๋๋ํฉ๋๋ค. ๋ ๋์ ์ฑ๋ฅ์ ์ํด, ์ปดํฌ๋ํธ๊ฐ ๋ ๋๋ง๋๊ธฐ ์ ์ ๋ช ์์ ์ผ๋ก ๋ฐ์ดํฐ ๋ก๋ฉ์ ์์ํ๋๋ก ํ๋ฆฌํ์นญ(pre-fetching) API๋ฅผ ์ฌ์ฉํ ์ ์์ต๋๋ค.
์ ๋ต 4: Render-as-You-Fetch ํจํด
์ด๊ฒ์ ๋ฆฌ์กํธ ํ์ด ๊ฐ๋ ฅํ๊ฒ ๊ถ์ฅํ๋ ๊ฐ์ฅ ์ง๋ณด๋๊ณ ์ฑ๋ฅ์ด ๋ฐ์ด๋ ํจํด์ ๋๋ค. ์ด๋ ์ผ๋ฐ์ ์ธ ๋ฐ์ดํฐ ํ์นญ ๋ชจ๋ธ์ ์์ ํ ๋ค์ง์ต๋๋ค.
- Fetch-on-Render (๋ฌธ์ ์ ): ์ปดํฌ๋ํธ ๋ ๋๋ง -> useEffect/ํ ์ด ํ์น ํธ๋ฆฌ๊ฑฐ. (์ํฐํด๋ก ์ด์ด์ง).
- Fetch-then-Render: ํ์น ํธ๋ฆฌ๊ฑฐ -> ๋๊ธฐ -> ๋ฐ์ดํฐ์ ํจ๊ป ์ปดํฌ๋ํธ ๋ ๋๋ง. (๋ ๋ซ์ง๋ง ์ฌ์ ํ ๋ ๋๋ง์ ์ฐจ๋จํ ์ ์์).
- Render-as-You-Fetch (ํด๊ฒฐ์ฑ ): ํ์น ํธ๋ฆฌ๊ฑฐ -> ์ฆ์ ์ปดํฌ๋ํธ ๋ ๋๋ง ์์. ๋ฐ์ดํฐ๊ฐ ์์ง ์ค๋น๋์ง ์์๋ค๋ฉด ์ปดํฌ๋ํธ๋ ์ผ์ ์ค๋จ๋จ.
๊ฐ๋ : ๋ฐ์ดํฐ ํ์นญ์ ์ปดํฌ๋ํธ ์๋ช ์ฃผ๊ธฐ์์ ์์ ํ ๋ถ๋ฆฌํฉ๋๋ค. ๋คํธ์ํฌ ์์ฒญ์ ๊ฐ๋ฅํ ๊ฐ์ฅ ๋น ๋ฅธ ์๊ฐ์ ์์ํฉ๋๋ค. ์๋ฅผ ๋ค์ด, ๋ผ์ฐํ ๋ ์ด์ด๋ ์ด๋ฒคํธ ํธ๋ค๋ฌ(๋งํฌ ํด๋ฆญ ๋ฑ)์์, ๋ฐ์ดํฐ๊ฐ ํ์ํ ์ปดํฌ๋ํธ๊ฐ ๋ ๋๋ง์ ์์ํ๊ธฐ๋ ์ ์ ๋ง์ ๋๋ค.
- // 1. ๋ผ์ฐํฐ๋ ์ด๋ฒคํธ ํธ๋ค๋ฌ์์ ํ์นญ ์์
- import { createProfileData } from './api';
- // ์ฌ์ฉ์๊ฐ ํ๋กํ ํ์ด์ง ๋งํฌ๋ฅผ ํด๋ฆญํ ๋:
- function onProfileLinkClick(userId) {
- const resource = createProfileData(userId);
- navigateTo(`/profile/${userId}`, { state: { resource } });
- }
- // 2. ํ์ด์ง ์ปดํฌ๋ํธ๊ฐ ๋ฆฌ์์ค๋ฅผ ๋ฐ์
- function ProfilePage() {
- // ์ด๋ฏธ ์์๋ ๋ฆฌ์์ค๋ฅผ ๊ฐ์ ธ์ต๋๋ค
- const resource = useLocation().state.resource;
- return (
- <Suspense fallback={<h1>ํ๋กํ ๋ก๋ฉ ์ค...</h1>}>
- <ProfileDetails resource={resource} />
- <ProfilePosts resource={resource} />
- </Suspense>
- );
- }
- // 3. ์์ ์ปดํฌ๋ํธ๊ฐ ๋ฆฌ์์ค์์ ์ฝ์
- function ProfileDetails({ resource }) {
- const user = resource.user.read(); // ์ฝ๊ฑฐ๋ ์ผ์ ์ค๋จ
- return <h1>{user.name}</h1>;
- }
- function ProfilePosts({ resource }) {
- const posts = resource.posts.read(); // ์ฝ๊ฑฐ๋ ์ผ์ ์ค๋จ
- return <ul>...</ul>;
- }
์ด ํจํด์ ์๋ฆ๋ค์์ ๊ทธ ํจ์จ์ฑ์ ์์ต๋๋ค. ์ฌ์ฉ์์ ๊ฒ์๋ฌผ ๋ฐ์ดํฐ์ ๋ํ ๋คํธ์ํฌ ์์ฒญ์ ์ฌ์ฉ์๊ฐ ํ์ ์๋๋ฅผ ๋ํ๋ด๋ ์ฆ์ ์์๋ฉ๋๋ค. `ProfilePage`์ ์๋ฐ์คํฌ๋ฆฝํธ ๋ฒ๋ค์ ๋ก๋ํ๊ณ ๋ฆฌ์กํธ๊ฐ ๋ ๋๋ง์ ์์ํ๋ ๋ฐ ๊ฑธ๋ฆฌ๋ ์๊ฐ์ ๋ฐ์ดํฐ ํ์นญ๊ณผ ๋ณ๋ ฌ๋ก ๋ฐ์ํฉ๋๋ค. ์ด๋ ์๋ฐฉ ๊ฐ๋ฅํ ๊ฑฐ์ ๋ชจ๋ ๋๊ธฐ ์๊ฐ์ ์ ๊ฑฐํฉ๋๋ค.
์ต์ ํ ์ ๋ต ๋น๊ต: ์ด๋ค ๊ฒ์ ์ ํํด์ผ ํ ๊น?
์ฌ๋ฐ๋ฅธ ์ ๋ต์ ์ ํํ๋ ๊ฒ์ ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ณต์ก์ฑ๊ณผ ์ฑ๋ฅ ๋ชฉํ์ ๋ฐ๋ผ ๋ค๋ฆ ๋๋ค.
- ๋ณ๋ ฌ ํ์นญ (`Promise.all` / ์๋ ์กฐ์ ):
- ์ฅ์ : ์ธ๋ถ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐ ํ์ ์์. ํจ๊ป ์์นํ ๋ฐ์ดํฐ ์๊ตฌ์ฌํญ์ ๋ํด ๊ฐ๋ ์ ์ผ๋ก ๊ฐ๋จํจ. ํ๋ก์ธ์ค์ ๋ํ ์์ ํ ์ ์ด.
- ๋จ์ : ์ํ, ์๋ฌ, ์บ์ฑ์ ์๋์ผ๋ก ๊ด๋ฆฌํ๊ธฐ ๋ณต์กํด์ง ์ ์์. ๊ฒฌ๊ณ ํ ๊ตฌ์กฐ ์์ด๋ ํ์ฅ์ฑ์ด ์ข์ง ์์.
- ์ต์ ์ฌ์ฉ์ฒ: ๊ฐ๋จํ ์ฌ์ฉ ์ฌ๋ก, ์๊ท๋ชจ ์ ํ๋ฆฌ์ผ์ด์ , ๋๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ค๋ฒํค๋๋ฅผ ํผํ๊ณ ์ถ์ ์ฑ๋ฅ์ด ์ค์ํ ์น์ .
- ๋ฐ์ดํฐ ํ์นญ ๋์ด์ฌ๋ฆฌ๊ธฐ:
- ์ฅ์ : ์ปดํฌ๋ํธ ํธ๋ฆฌ์์ ๋ฐ์ดํฐ ํ๋ฆ์ ๊ตฌ์ฑํ๊ธฐ ์ข์. ํน์ ๋ทฐ์ ๋ํ ํ์นญ ๋ก์ง์ ์ค์ ์ง์คํํจ.
- ๋จ์ : prop ๋๋ฆด๋ง์ผ๋ก ์ด์ด์ง๊ฑฐ๋ ๋ฐ์ดํฐ๋ฅผ ์ ๋ฌํ๊ธฐ ์ํด ์ํ ๊ด๋ฆฌ ์๋ฃจ์ ์ด ํ์ํ ์ ์์. ๋ถ๋ชจ ์ปดํฌ๋ํธ๊ฐ ๋น๋ํด์ง ์ ์์.
- ์ต์ ์ฌ์ฉ์ฒ: ์ฌ๋ฌ ํ์ ์ปดํฌ๋ํธ๊ฐ ๊ณตํต ๋ถ๋ชจ์์ ๊ฐ์ ธ์ฌ ์ ์๋ ๋ฐ์ดํฐ์ ๋ํ ์์กด์ฑ์ ๊ณต์ ํ ๋.
- ๋ฐ์ดํฐ ํ์นญ ๋ผ์ด๋ธ๋ฌ๋ฆฌ (๋ฆฌ์กํธ ์ฟผ๋ฆฌ, SWR):
- ์ฅ์ : ๊ฐ์ฅ ๊ฒฌ๊ณ ํ๊ณ ๊ฐ๋ฐ์ ์นํ์ ์ธ ์๋ฃจ์ . ์บ์ฑ, ์ค๋ณต ์ ๊ฑฐ, ๋ฐฑ๊ทธ๋ผ์ด๋ ๋ฆฌํ์นญ, ์๋ฌ ์ํ๋ฅผ ๊ธฐ๋ณธ์ ์ผ๋ก ์ฒ๋ฆฌํจ. ๋ณด์ผ๋ฌํ๋ ์ดํธ๋ฅผ ๋ํญ ์ค์ฌ์ค.
- ๋จ์ : ํ๋ก์ ํธ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์์กด์ฑ์ ์ถ๊ฐํจ. ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ํน์ API๋ฅผ ๋ฐฐ์์ผ ํจ.
- ์ต์ ์ฌ์ฉ์ฒ: ๋๋ถ๋ถ์ ์ต์ ๋ฆฌ์กํธ ์ ํ๋ฆฌ์ผ์ด์ . ์ฌ์ํ์ง ์์ ๋ฐ์ดํฐ ์๊ตฌ์ฌํญ์ด ์๋ ๋ชจ๋ ํ๋ก์ ํธ์ ๊ธฐ๋ณธ ์ ํ์ด ๋์ด์ผ ํจ.
- Render-as-You-Fetch:
- ์ฅ์ : ์ต๊ณ ์ฑ๋ฅ์ ํจํด. ์ปดํฌ๋ํธ ์ฝ๋ ๋ก๋ฉ๊ณผ ๋ฐ์ดํฐ ํ์นญ์ ์ค์ฒฉ์์ผ ๋ณ๋ ฌ์ฑ์ ๊ทน๋ํํจ.
- ๋จ์ : ์ฌ๊ณ ๋ฐฉ์์ ์๋นํ ์ ํ์ด ํ์ํจ. Relay๋ Next.js์ ๊ฐ์ด ์ด ํจํด์ด ๋ด์ฅ๋ ํ๋ ์์ํฌ๋ฅผ ์ฌ์ฉํ์ง ์๋ ๊ฒฝ์ฐ ์ค์ ์ ๋ ๋ง์ ๋ณด์ผ๋ฌํ๋ ์ดํธ๊ฐ ํฌํจ๋ ์ ์์.
- ์ต์ ์ฌ์ฉ์ฒ: ๋งค ๋ฐ๋ฆฌ์ด๊ฐ ์ค์ํ ์ง์ฐ ์๊ฐ์ ๋ฏผ๊ฐํ ์ ํ๋ฆฌ์ผ์ด์ . ๋ผ์ฐํ ๊ณผ ๋ฐ์ดํฐ ํ์นญ์ ํตํฉํ๋ ํ๋ ์์ํฌ๊ฐ ์ด ํจํด์ ์ด์์ ์ธ ํ๊ฒฝ์.
๊ธ๋ก๋ฒ ๊ณ ๋ ค์ฌํญ ๋ฐ ๋ชจ๋ฒ ์ฌ๋ก
์ ์ธ๊ณ ์ฌ์ฉ์๋ฅผ ๋์์ผ๋ก ๊ตฌ์ถํ ๋ ์ํฐํด์ ์ ๊ฑฐํ๋ ๊ฒ์ ์์ผ๋ฉด ์ข์ ๊ฒ์ด ์๋๋ผ ํ์์ ์ ๋๋ค.
- ์ง์ฐ ์๊ฐ์ ๊ท ์ผํ์ง ์์: 200ms์ ์ํฐํด์ ์๋ฒ ๊ทผ์ฒ์ ์ฌ์ฉ์์๊ฒ๋ ๊ฑฐ์ ๋์ ๋์ง ์์ ์ ์์ง๋ง, ์ง์ฐ ์๊ฐ์ด ๊ธด ๋ชจ๋ฐ์ผ ์ธํฐ๋ท์ ์ฌ์ฉํ๋ ๋ค๋ฅธ ๋๋ฅ์ ์ฌ์ฉ์์๊ฒ๋ ๋์ผํ ์ํฐํด์ด ๋ก๋ ์๊ฐ์ ๋ช ์ด๋ฅผ ์ถ๊ฐํ ์ ์์ต๋๋ค. ์์ฒญ์ ๋ณ๋ ฌํํ๋ ๊ฒ์ด ๋์ ์ง์ฐ ์๊ฐ์ ์ํฅ์ ์ํํ๋ ๊ฐ์ฅ ํจ๊ณผ์ ์ธ ๋จ์ผ ๋ฐฉ๋ฒ์ ๋๋ค.
- ์ฝ๋ ๋ถํ ์ํฐํด: ์ํฐํด์ ๋ฐ์ดํฐ์๋ง ๊ตญํ๋์ง ์์ต๋๋ค. ์ผ๋ฐ์ ์ธ ํจํด์ `React.lazy()`๋ก ์ปดํฌ๋ํธ ๋ฒ๋ค์ ๋ก๋ํ ๋ค์, ํด๋น ์ปดํฌ๋ํธ๊ฐ ์์ฒด ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ค๋ ๊ฒ์ ๋๋ค. ์ด๊ฒ์ ์ฝ๋ -> ๋ฐ์ดํฐ ์ํฐํด์ ๋๋ค. Render-as-You-Fetch ํจํด์ ์ฌ์ฉ์๊ฐ ํ์ํ ๋ ์ปดํฌ๋ํธ์ ํด๋น ๋ฐ์ดํฐ๋ฅผ ๋ชจ๋ ๋ฏธ๋ฆฌ ๋ก๋ํ์ฌ ์ด ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๋ ๋ฐ ๋์์ด ๋ฉ๋๋ค.
- ์ฐ์ํ ์๋ฌ ์ฒ๋ฆฌ: ๋ฐ์ดํฐ๋ฅผ ๋ณ๋ ฌ๋ก ๊ฐ์ ธ์ฌ ๋ ๋ถ๋ถ์ ์ธ ์คํจ๋ฅผ ๊ณ ๋ คํด์ผ ํฉ๋๋ค. ์ฌ์ฉ์ ๋ฐ์ดํฐ๋ ๋ก๋๋์์ง๋ง ๊ฒ์๋ฌผ์ด ์คํจํ๋ฉด ์ด๋ป๊ฒ ๋ ๊น์? UI๋ ์ด๋ฅผ ์ฐ์ํ๊ฒ ์ฒ๋ฆฌํ ์ ์์ด์ผ ํ๋ฉฐ, ์๋ง๋ ๊ฒ์๋ฌผ ์น์ ์ ์๋ฌ ๋ฉ์์ง์ ํจ๊ป ์ฌ์ฉ์ ํ๋กํ์ ๋ณด์ฌ์ค ์ ์์ต๋๋ค. ๋ฆฌ์กํธ ์ฟผ๋ฆฌ์ ๊ฐ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ ์ฟผ๋ฆฌ๋ณ ์๋ฌ ์ํ๋ฅผ ์ฒ๋ฆฌํ๊ธฐ ์ํ ๋ช ํํ ํจํด์ ์ ๊ณตํฉ๋๋ค.
- ์๋ฏธ ์๋ Fallbacks: ๋ฐ์ดํฐ๊ฐ ๋ก๋๋๋ ๋์ ์ข์ ์ฌ์ฉ์ ๊ฒฝํ์ ์ ๊ณตํ๊ธฐ ์ํด `
`์ `fallback` prop์ ์ฌ์ฉํ์ธ์. ์ผ๋ฐ์ ์ธ ์คํผ๋ ๋์ ์ต์ข UI์ ๋ชจ์์ ๋ชจ๋ฐฉํ๋ ์ค์ผ๋ ํค ๋ก๋๋ฅผ ์ฌ์ฉํ์ธ์. ์ด๋ ์ธ์ง ์ฑ๋ฅ์ ํฅ์์ํค๊ณ ๋คํธ์ํฌ๊ฐ ๋๋ฆด ๋๋ ์ ํ๋ฆฌ์ผ์ด์ ์ด ๋ ๋น ๋ฅด๊ฒ ๋๊ปด์ง๊ฒ ๋ง๋ญ๋๋ค.
๊ฒฐ๋ก
๋ฆฌ์กํธ ์์คํ์ค ์ํฐํด์ ํนํ ์ ์ธ๊ณ ์ฌ์ฉ์ ๊ธฐ๋ฐ์ ๋ํด ์ฌ์ฉ์ ๊ฒฝํ์ ์ ํ์ํฌ ์ ์๋ ๋ฏธ๋ฌํ์ง๋ง ์ค์ํ ์ฑ๋ฅ ๋ณ๋ชฉ ํ์์ ๋๋ค. ์ด๋ ์์ฐ์ค๋ฝ์ง๋ง ๋นํจ์จ์ ์ธ ์์ฐจ์ , ์ค์ฒฉ ๋ฐ์ดํฐ ํ์นญ ํจํด์์ ๋ฐ์ํฉ๋๋ค. ์ด ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๋ ์ด์ ๋ ์ฌ๊ณ ์ ์ ํ์ ๋๋ค: ๋ ๋๋ง ์ ํ์นญ์ ๋ฉ์ถ๊ณ , ๊ฐ๋ฅํ ํ ๋นจ๋ฆฌ, ๋ณ๋ ฌ๋ก ํ์นญ์ ์์ํ์ธ์.
์ฐ๋ฆฌ๋ ์๋ ํ๋ก๋ฏธ์ค ์กฐ์ ์์๋ถํฐ ๊ณ ํจ์จ์ Render-as-You-Fetch ํจํด์ ์ด๋ฅด๊ธฐ๊น์ง ๋ค์ํ ๊ฐ๋ ฅํ ์ ๋ต์ ํ๊ตฌํ์ต๋๋ค. ๋๋ถ๋ถ์ ์ต์ ์ ํ๋ฆฌ์ผ์ด์ ์ ๊ฒฝ์ฐ, TanStack Query๋ SWR๊ณผ ๊ฐ์ ์ ์ฉ ๋ฐ์ดํฐ ํ์นญ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฑํํ๋ ๊ฒ์ด ์ฑ๋ฅ, ๊ฐ๋ฐ์ ๊ฒฝํ, ๊ทธ๋ฆฌ๊ณ ์บ์ฑ ๋ฐ ์ค๋ณต ์ ๊ฑฐ์ ๊ฐ์ ๊ฐ๋ ฅํ ๊ธฐ๋ฅ ๊ฐ์ ์ต์์ ๊ท ํ์ ์ ๊ณตํฉ๋๋ค.
์ค๋ ๋น์ฅ ์ ํ๋ฆฌ์ผ์ด์ ์ ๋คํธ์ํฌ ํญ์ ๊ฐ์ฌํ๊ธฐ ์์ํ์ธ์. ๊ทธ ํน์ง์ ์ธ ๊ณ๋จ์ ํจํด์ ์ฐพ์๋ณด์ธ์. ๋ฐ์ดํฐ ํ์นญ ์ํฐํด์ ์๋ณํ๊ณ ์ ๊ฑฐํจ์ผ๋ก์จ, ์ฌ๋ฌ๋ถ์ ์ ์ธ๊ณ ์ด๋์ ์๋ ์ฌ์ฉ์์๊ฒ ํจ์ฌ ๋ ๋น ๋ฅด๊ณ , ๋ ์ ์ฐํ๋ฉฐ, ๋ ํ๋ ฅ์ ์ธ ์ ํ๋ฆฌ์ผ์ด์ ์ ์ ๊ณตํ ์ ์์ต๋๋ค.