React.Suspense์ ๋ํด ์ค๋ช
ํด์ฃผ์ธ์.์๋: ๋น๋๊ธฐ ๋ฐ์ดํฐ ๋ก๋ฉ ๋ฐ ๋ ๋๋ง ๊ณผ์ ์ ์ดํดํ๊ณ Suspense๋ฅผ ์ฌ์ฉํ ์ ์๋์ง ํ์ธํ๋ ์ง๋ฌธ
๋์ ๋ต์
๋ฆฌ์กํธ์ Suspense๋ ๋น๋๊ธฐ์ ์ผ๋ก ๋ก๋๋๋ ์ปดํฌ๋ํธ๋ฅผ '๋ก๋ฉ ์ค' ์ํ๋ก ์ฒ๋ฆฌํ ์ ์๋๋ก ๋์์ฃผ๋ ๊ธฐ๋ฅ์ ๋๋ค.
์ฆ, ํน์ ์ปดํฌ๋ํธ๊ฐ ๋ฐ์ดํฐ๋ฅผ ๋ถ๋ฌ์ค๊ฑฐ๋ ์ฝ๋ ์คํ๋ฆฌํ ์ผ๋ก ์ธํด ์์ง ์ค๋น๋์ง ์์์ ๋, ๊ทธ๋์ ๋ณด์ฌ์ค fallback UI(๋๊ธฐ ํ๋ฉด)๋ฅผ ์ง์ ํด์ฃผ๋ ์ญํ ์ ํฉ๋๋ค.์๋ฅผ ๋ค์ด, Lazy Loading๋ ์ปดํฌ๋ํธ๋ฅผ ๋ก๋ํ ๋ React๋ ํด๋น ์ปดํฌ๋ํธ๊ฐ ์์ ํ ๋ก๋๋ ๋๊น์ง ๊ธฐ๋ค๋ฆฌ์ง ์๊ณ ,
Suspense๊ฐ ๊ฐ์ธ๊ณ ์๋ ๋์ ์ง์ ๋ fallback UI๋ฅผ ๋จผ์ ๋ ๋๋งํฉ๋๋ค.
์ค๋น๊ฐ ์๋ฃ๋๋ฉด ์ค์ ์ปดํฌ๋ํธ๋ก ๊ต์ฒด๋ฉ๋๋ค.
์ฃผ์ด์ง ๋ต์ (๋ชจ๋ฒ ๋ต์)
๋ค. ๋ฆฌ์กํธ์ Suspense๋ ๋น๋๊ธฐ ๋ฐ์ดํฐ๋ฅผ ๋ก๋ฉํ ๋, ๊ทธ๋ฆฌ๊ณ ๋ก๋ฉ ์ํ๋ฅผ ํ์ํ ๋ ์ฌ์ฉํ๋ฉด ์ข์ ์ ์ธํ ์ฝ๋์ ์ผ์ข ์ ๋๋ค.
Suspense์๋ fallback ์์ฑ์ ์ค ์ ์๋๋ฐ ์ด ์์ฑ์ด ๋ฐ๋ก ๋ก๋ฉ ์ํ์ผ ๋ ํ๋ฉด์ ๋ณด์ฌ์ค ์์๊ฐ ๋ฉ๋๋ค.์ ์ธํ ์ฝ๋์ด๋๋งํผ ๊ธฐ์กด์๋ ๋ก๋ฉ ์ํ ํ์๋ฅผ ์ํด isLoading์ผ๋ก ์ํ๋ฅผ ๊ด๋ฆฌํด ๋ก๋ฉ ํ๋ฉด์ ์กฐ๊ฑด๋ถ ๋ ๋๋ง์ ํด์ฃผ์๋ค๋ฉด, ์ด์ ๋ ํ๊ทธ์ ์์ฑ์ ์ฃผ๋ ๊ฒ๋ง์ผ๋ก ๊ฐ๊ฒฐํ๊ฒ ๊ตฌํํ ์ ์๋ค๋ ์ฅ์ ์ ๊ฐ์ง๊ณ ์์ต๋๋ค.
๋ค๋ง ์ฃผ์ํ ์ ์ ํน์ ๋น๋๊ธฐ ๋ฐ์ดํฐ ํธ์ถ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ง Suspense๋ฅผ ์ง์ํ๊ธฐ ๋๋ฌธ์ ์ ์์๋ณด๊ณ ์ ์ฉํด์ผ ํฉ๋๋ค.
๋น๋๊ธฐ ์์
์ ์ฒ๋ฆฌํ๋ ๋์ ๋์ฒด UI ํ์
Suspense๋ ๋น๋๊ธฐ ๋ฐ์ดํฐ๊ฐ ์ค๋น๋์ง ์์ ์ํ์์ fallback UI๋ฅผ ๋ ๋๋งํ๋ค.
๋ฐ์ดํฐ๊ฐ ์ค๋น๋๋ฉด ๋์ฒด UI๋ฅผ ์ค์ ์ฝํ
์ธ ๋ก ๋์ฒดํ๋ค.
์ฝ๋ ์คํ๋ฆฌํ
React.lazy์ ํจ๊ป ์ฌ์ฉํ๋ฉด ํ์ํ ์์ ์ ์ปดํฌ๋ํธ๋ฅผ ๋์ ์ผ๋ก ๋ก๋ํ ์ ์๋ค.
์ด๋ ์ด๊ธฐ ๋ฒ๋ค ํฌ๊ธฐ๋ฅผ ์ค์ด๊ณ ์ฑ์ ์ฑ๋ฅ์ ํฅ์์ํค๋ ๋ฐ ์ ์ฉํ๋ค.
๋๊ธฐ์ ์ธ ์ฌ์ฉ์ ๊ฒฝํ ์ ๊ณต
๋ฐ์ดํฐ๋ฅผ ๋น๋๊ธฐ๋ก ๊ฐ์ ธ์ฌ ๋, ๊น๋นก์ด๋ ํ๋ฉด ๋์ ์ค๋ฌด์คํ ๋ก๋ฉ ๊ฒฝํ์ ์ ๊ณตํ๋ค.
<Suspense fallback={<Loading />}>
<MyComponent />
<Suspense/>
fallback: ๋น๋๊ธฐ ์์
์ด ์๋ฃ๋๊ธฐ ์ ์ ํ์ํ ๋์ฒด UI์ด๋ค. ์ฃผ๋ก ๋ก๋ฉ ์ธ๋์ผ์ดํฐ(์คํผ๋, ๋ก๋ฉ ํ
์คํธ ๋ฑ)๋ฅผ ์ฌ์ฉํ๋ค.React.lazy๋ฅผ ์ด์ฉํ ์ฝ๋ ์คํ๋ฆฌํ
React.lazy์ Suspense๋ฅผ ์กฐํฉํ๋ฉด ์ปดํฌ๋ํธ๋ฅผ ๋์ ์ผ๋ก ๋ก๋ํ ์ ์๋ค.
import React, { Suspense } from "react";
const LazyComponent = React.lazy(() => import("./MyComponent"));
function App() {
return (
<Suspense fallback={<div>Loading...</div>}>
<LazyComponent />
</Suspense>
);
}
LazyComponent๋ MyComponent๋ฅผ ๋์ ์ผ๋ก ๋ก๋ํ๋ฉฐ, ๋ก๋๋๋ ๋์ "Loading..."์ ํ์ํ๋ค.๋ฐ์ดํฐ ํ์นญ (React 18 ์ด์)
React 18๋ถํฐ Suspense๋ ์๋ฒ์ ํด๋ผ์ด์ธํธ์์ ๋ฐ์ดํฐ๋ฅผ ํ์นญํ ๋ ์ฌ์ฉํ ์ ์๋ค.
์๋ฒ ์ปดํฌ๋ํธ์ use() ํจ์๋ก ๋ฐ์ดํฐ๋ฅผ ๊ธฐ๋ค๋ฆฌ๋ ์์
์ด ๊ฐ๋ฅํ๋ค.
import React, { Suspense } from "react";
async function fetchData() {
return new Promise((resolve) => setTimeout(() => resolve("Hello, Server Component!"), 2000));
}
function MyComponent() {
const data = use(fetchData()); // ์๋ฒ ์ปดํฌ๋ํธ์์๋ง ์ฌ์ฉ ๊ฐ๋ฅ
return <div>{data}</div>;
}
export default function App() {
return (
<Suspense fallback={<div>Loading data...</div>}>
<MyComponent />
</Suspense>
);
}
โญ
use()ํจ์๋?
use()๋ React 18๋ถํฐ ์ง์๋๋ ํจ์๋ก, React ์๋ฒ ์ปดํฌ๋ํธ(Server Component) ํ๊ฒฝ์์ ๋น๋๊ธฐ ๋ฐ์ดํฐ๋ฅผ ์ฝ๊ฒ ๊ฐ์ ธ์ค๋ ๋ฐ ์ฌ์ฉ๋๋ค.use()๋ Promise๋ฅผ ๋ฐ์์ ๊ทธ ๊ฒฐ๊ณผ๋ฅผ ๋ฐํํ๋ฉฐ, React์ Suspense์ ๊ฒฐํฉํ์ฌ ๋น๋๊ธฐ ์์ ์ ์ฒ๋ฆฌํ๋ค.- ์ด ํจ์๋ ํด๋ผ์ด์ธํธ ์ปดํฌ๋ํธ์์๋ ์ฌ์ฉํ ์ ์๊ณ , ์๋ฒ ์ปดํฌ๋ํธ ์ ์ฉ์ด๋ค.
โญ
use()ํจ์์ ์ฃผ์ ํน์ง
- Promise๋ฅผ ๊ธฐ๋ค๋ฆฐ๋ค.
use()ํจ์๋ ์ ๋ฌ๋ฐ์ Promise๊ฐ ํด๊ฒฐ๋ ๋๊น์ง ๊ธฐ๋ค๋ฆฌ๊ณ , ๊ทธ ๊ฒฐ๊ณผ๋ฅผ ๋ฐํํ๋ค.- Promise๊ฐ ํด๊ฒฐ๋์ง ์์์ ๊ฒฝ์ฐ, React๋ ํด๋น ์ปดํฌ๋ํธ๋ฅผ ์ค๋จ(suspend)ํ๊ณ
Suspense์fallbackUI๋ฅผ ๋ ๋๋งํ๋ค.- Suspense์์ ํตํฉ
use()๋ React ์๋ฒ ์ปดํฌ๋ํธ์์Suspense๋ฅผ ์ฌ์ฉํด ๋น๋๊ธฐ ๋ฐ์ดํฐ๋ฅผ ๋ก๋ฉํ๋ ๋์ ๋์ฒด UI๋ฅผ ๋ณด์ฌ์ค ์ ์๋๋ก ์ค๊ณ๋์๋ค.- ์๋ฒ ์ปดํฌ๋ํธ ์ ์ฉ
use()๋ ํด๋ผ์ด์ธํธ ์ปดํฌ๋ํธ์์๋ ์ฌ์ฉํ ์ ์๋ค.- React์ ์๋ฒ ๋ ๋๋ง ํ๊ฒฝ(์: Next.js App Router)์์๋ง ๋์ํ๋ค.
โญ
use()ํจ์์ ์ฃผ์ ์ด์
- ์ฝ๋ ๊ฐ๊ฒฐํ
๋น๋๊ธฐ ๋ฐ์ดํฐ ์ฒ๋ฆฌ ์ฝ๋๋ฅผ ๋จ์ํํ๋ค.
๊ธฐ์กด์useEffect์useState๋ฅผ ์กฐํฉํ์ฌ ์์ฑํด์ผ ํ๋ ๋ก์ง์ ์ค์ผ ์ ์๋ค.- React์ ๋น๋๊ธฐ ์ฒ๋ฆฌ์ ํตํฉ
React์Suspense์ ๊ฒฐํฉํ์ฌ ๋น๋๊ธฐ ๋ฐ์ดํฐ ๋ก๋ฉ ์ค ์ ์ ํ ๋์ฒด UI๋ฅผ ์ ๊ณตํ ์ ์๋ค.- ์๋ฒ ๋ ๋๋ง ์ต์ ํ
์๋ฒ ์ปดํฌ๋ํธ์์ ๋ฐ์ดํฐ๋ฅผ ๋ก๋ํ๋ฏ๋ก ํด๋ผ์ด์ธํธ๋ก ๋ณด๋ด๋ HTML์ด ์ด๋ฏธ ์ค๋น๋ ๋ฐ์ดํฐ๋ฅผ ํฌํจํ๊ฒ ๋๋ค. ์ด๋ก ์ธํด ์ด๊ธฐ ๋ก๋ฉ ์๊ฐ์ด ๋จ์ถ๋๋ค.
๋น๋๊ธฐ ์ฒ๋ฆฌ ์ํ ๊ฐ์ง
Suspense๋ ์์ ์ปดํฌ๋ํธ์์ ๋น๋๊ธฐ ์์
์ด ๋ฐ์ํ์์ ๊ฐ์งํ๊ณ , ํด๋น ์์
์ด ์๋ฃ๋ ๋๊น์ง ๋ ๋๋ง์ ์ค๋จํ๋ค.
๋์ฒด UI ๋ ๋๋ง
์์
์ด ์๋ฃ๋ ๋๊น์ง fallback์ผ๋ก ์ง์ ๋ ์ปดํฌ๋ํธ๋ฅผ ๋ ๋๋งํ๋ค.
์์
์๋ฃ ํ ๋ ๋๋ง ์ฌ๊ฐ
๋น๋๊ธฐ ์์
์ด ์๋ฃ๋๋ฉด, Suspense๋ ์์ ์ปดํฌ๋ํธ๋ฅผ ๋ค์ ๋ ๋๋งํ์ฌ ์ต์ข
๋ฐ์ดํฐ๋ฅผ ํ๋ฉด์ ํ์ํ๋ค.
๋๊ธฐ์ ๋ฐ์ดํฐ ํ์นญ์์ ๋์ํ์ง ์์
Suspense๋ ๋น๋๊ธฐ ์์
๊ณผ ํจ๊ป ์ฌ์ฉํ๋๋ก ์ค๊ณ๋์๋ค.
๋ฐ๋ผ์ ๋๊ธฐ์ ์ผ๋ก ๋ฐ์ดํฐ๋ฅผ ํ์นญํ๋ฉด ์ ๋๋ก ๋์ํ์ง ์๋๋ค.
์๋ํํฐ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ํ์
Suspense ์์ฒด๋ ๋ฐ์ดํฐ ํ์นญ ๋ก์ง์ ์ ๊ณตํ์ง ์๋๋ค.
react-query, Relay, SWR ๊ฐ์ ์๋ํํฐ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํ์ฌ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์์ผ ํ๋ค.
SSR(์๋ฒ ์ฌ์ด๋ ๋ ๋๋ง) ์ ํ
React 18 ์ด์ ๊น์ง Suspense๋ SSR์์ ์์ ํ ์ง์๋์ง ์์๋ค.
React 18์์๋ ์๋ฒ ์ปดํฌ๋ํธ์ ํจ๊ป ์ด ์ ํ์ด ํด๊ฒฐ๋์๋ค.
React 18์์ Suspense๋ ๋ ๊ฐ๋ ฅํ ๊ธฐ๋ฅ์ ์ ๊ณตํ๋ฉฐ, ๋ฐ์ดํฐ ํ์นญ๊ณผ SSR์์ ์ฌ์ฉํ ์ ์๋ค.
์์: React Query์ ํจ๊ป ์ฌ์ฉ
import { Suspense } from "react";
import { useQuery } from "react-query";
function fetchData() {
return fetch("https://api.example.com/data").then(res => res.json());
}
function MyComponent() {
const { data } = useQuery("myData", fetchData);
return <div>{data.message}</div>;
}
function App() {
return (
<Suspense fallback={<div>Loading...</div>}>
<MyComponent />
</Suspense>
);
}