์ค์ฒฉ๋ ์ปดํฌ๋ํธ ํธ๋ฆฌ์์ ๋ณต์กํ ๋ก๋ฉ ์ํ๋ฅผ ๊ด๋ฆฌํ๊ธฐ ์ํ React Suspense๋ฅผ ์์๋ณด์ธ์. ํจ๊ณผ์ ์ธ ์ค์ฒฉ ๋ก๋ฉ ๊ด๋ฆฌ๋ก ๋ถ๋๋ฌ์ด ์ฌ์ฉ์ ๊ฒฝํ์ ๋ง๋๋ ๋ฐฉ๋ฒ์ ๋ฐฐ์๋๋ค.
React Suspense ๋ก๋ฉ ์ํ ๊ตฌ์ฑ ํธ๋ฆฌ: ์ค์ฒฉ๋ ๋ก๋ฉ ๊ด๋ฆฌ
React Suspense๋ ์ฃผ๋ก ๋ฐ์ดํฐ ๊ฐ์ ธ์ค๊ธฐ์ ๊ฐ์ ๋น๋๊ธฐ ์์ ์ ๋ ์ํํ๊ฒ ์ฒ๋ฆฌํ๊ธฐ ์ํด ๋์ ๋ ๊ฐ๋ ฅํ ๊ธฐ๋ฅ์ ๋๋ค. ๋ฐ์ดํฐ ๋ก๋๋ฅผ ๊ธฐ๋ค๋ฆฌ๋ ๋์ ์ปดํฌ๋ํธ ๋ ๋๋ง์ "์ผ์ ์ค๋จ"ํ๊ณ , ๊ทธ๋์ ๋์ฒด UI๋ฅผ ํ์ํ ์ ์์ต๋๋ค. ์ด๋ UI์ ์ฌ๋ฌ ๋ถ๋ถ์ด ๋ค์ํ ์์ค๋ก๋ถํฐ ๋น๋๊ธฐ ๋ฐ์ดํฐ์ ์์กดํ๋ ๋ณต์กํ ์ปดํฌ๋ํธ ํธ๋ฆฌ์์ ํนํ ์ ์ฉํฉ๋๋ค. ์ด ๊ธ์์๋ ์ค์ฒฉ๋ ์ปดํฌ๋ํธ ๊ตฌ์กฐ ๋ด์์ Suspense๋ฅผ ํจ๊ณผ์ ์ผ๋ก ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ์ ๊น์ด ์๊ฒ ๋ค๋ฃจ๊ณ , ์ผ๋ฐ์ ์ธ ๋ฌธ์ ๋ค์ ํด๊ฒฐํ๋ฉฐ ์ค์ฉ์ ์ธ ์์ ๋ฅผ ์ ๊ณตํฉ๋๋ค.
React Suspense์ ์ดํด์ ์ฅ์
์ค์ฒฉ ์๋๋ฆฌ์ค๋ฅผ ์ดํด๋ณด๊ธฐ ์ ์, React Suspense์ ํต์ฌ ๊ฐ๋ ์ ๋ค์ ์ง์ด๋ณด๊ฒ ์ต๋๋ค.
React Suspense๋ ๋ฌด์์ธ๊ฐ?
Suspense๋ ์ฝ๋๊ฐ ๋ก๋๋๊ธฐ๋ฅผ "๊ธฐ๋ค๋ฆฌ๊ณ ", ๊ธฐ๋ค๋ฆฌ๋ ๋์ ํ์ํ ๋ก๋ฉ ์ํ(fallback)๋ฅผ ์ ์ธ์ ์ผ๋ก ์ง์ ํ ์ ์๊ฒ ํด์ฃผ๋ React ์ปดํฌ๋ํธ์
๋๋ค. React.lazy
๋ฅผ ์ฌ์ฉํ๋ ์ง์ฐ ๋ก๋ฉ ์ปดํฌ๋ํธ ๋ฐ Suspense์ ํตํฉ๋๋ ๋ฐ์ดํฐ ๊ฐ์ ธ์ค๊ธฐ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ํจ๊ป ์๋ํฉ๋๋ค.
Suspense ์ฌ์ฉ์ ์ด์ :
- ํฅ์๋ ์ฌ์ฉ์ ๊ฒฝํ: ๋น ํ๋ฉด ๋์ ์๋ฏธ ์๋ ๋ก๋ฉ ํ์๊ธฐ๋ฅผ ๋ณด์ฌ์ฃผ์ด ์ฑ์ด ๋ ๋ฐ์์ ์ผ๋ก ๋๊ปด์ง๊ฒ ํฉ๋๋ค.
- ์ ์ธ์ ๋ก๋ฉ ์ํ: ์ปดํฌ๋ํธ ํธ๋ฆฌ์์ ์ง์ ๋ก๋ฉ ์ํ๋ฅผ ์ ์ํ์ฌ ์ฝ๋๋ฅผ ์ฝ๊ณ ์ดํดํ๊ธฐ ์ฝ๊ฒ ๋ง๋ญ๋๋ค.
- ์ฝ๋ ๋ถํ : Suspense๋ ์ฝ๋ ๋ถํ (
React.lazy
์ฌ์ฉ)๊ณผ ์ํํ๊ฒ ์๋ํ์ฌ ์ด๊ธฐ ๋ก๋ ์๊ฐ์ ๊ฐ์ ํฉ๋๋ค. - ๊ฐ์ํ๋ ๋น๋๊ธฐ ๋ฐ์ดํฐ ๊ฐ์ ธ์ค๊ธฐ: Suspense๋ ํธํ๋๋ ๋ฐ์ดํฐ ๊ฐ์ ธ์ค๊ธฐ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ํตํฉ๋์ด ๋ฐ์ดํฐ ๋ก๋ฉ์ ๋ํ ๋ณด๋ค ๊ฐ์ํ๋ ์ ๊ทผ ๋ฐฉ์์ ๊ฐ๋ฅํ๊ฒ ํฉ๋๋ค.
๊ณผ์ : ์ค์ฒฉ๋ ๋ก๋ฉ ์ํ
Suspense๊ฐ ์ ๋ฐ์ ์ผ๋ก ๋ก๋ฉ ์ํ๋ฅผ ๋จ์ํํ์ง๋ง, ๊น๊ฒ ์ค์ฒฉ๋ ์ปดํฌ๋ํธ ํธ๋ฆฌ์์ ๋ก๋ฉ ์ํ๋ฅผ ๊ด๋ฆฌํ๋ ๊ฒ์ ๋ณต์กํด์ง ์ ์์ต๋๋ค. ๋ถ๋ชจ ์ปดํฌ๋ํธ๊ฐ ์ผ๋ถ ์ด๊ธฐ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์จ ๋ค์, ๊ฐ๊ฐ ์์ฒด ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ค๋ ์์ ์ปดํฌ๋ํธ๋ค์ ๋ ๋๋งํ๋ ์๋๋ฆฌ์ค๋ฅผ ์์ํด ๋ณด์ญ์์ค. ๋ถ๋ชจ ์ปดํฌ๋ํธ๋ ๋ฐ์ดํฐ๋ฅผ ํ์ํ์ง๋ง ์์ ์ปดํฌ๋ํธ๋ค์ ์ฌ์ ํ ๋ก๋ฉ ์ค์ธ ์ํฉ์ด ๋ฐ์ํ์ฌ, ์ผ๊ด์ฑ ์๋ ์ฌ์ฉ์ ๊ฒฝํ์ ์ด๋ํ ์ ์์ต๋๋ค.
๋ค์๊ณผ ๊ฐ์ ๋จ์ํ๋ ์ปดํฌ๋ํธ ๊ตฌ์กฐ๋ฅผ ๊ณ ๋ คํด ๋ณด์ธ์:
<ParentComponent>
<ChildComponent1>
<GrandChildComponent />
</ChildComponent1>
<ChildComponent2 />
</ParentComponent>
์ด ์ปดํฌ๋ํธ๋ค์ ๊ฐ๊ฐ ๋น๋๊ธฐ์ ์ผ๋ก ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ฌ ์ ์์ต๋๋ค. ์ฐ๋ฆฌ๋ ์ด๋ฌํ ์ค์ฒฉ๋ ๋ก๋ฉ ์ํ๋ฅผ ์ํํ๊ฒ ์ฒ๋ฆฌํ ์ ๋ต์ด ํ์ํฉ๋๋ค.
Suspense๋ฅผ ์ด์ฉํ ์ค์ฒฉ ๋ก๋ฉ ๊ด๋ฆฌ ์ ๋ต
๋ค์์ ์ค์ฒฉ๋ ๋ก๋ฉ ์ํ๋ฅผ ํจ๊ณผ์ ์ผ๋ก ๊ด๋ฆฌํ๊ธฐ ์ํด ์ฌ์ฉํ ์ ์๋ ๋ช ๊ฐ์ง ์ ๋ต์ ๋๋ค:
1. ๊ฐ๋ณ Suspense ๊ฒฝ๊ณ
๊ฐ์ฅ ๊ฐ๋จํ ์ ๊ทผ ๋ฐฉ์์ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ค๋ ๊ฐ ์ปดํฌ๋ํธ๋ฅผ ์์ฒด <Suspense>
๊ฒฝ๊ณ๋ก ๊ฐ์ธ๋ ๊ฒ์
๋๋ค. ์ด๋ฅผ ํตํด ๊ฐ ์ปดํฌ๋ํธ๋ ๋
๋ฆฝ์ ์ผ๋ก ์์ ์ ๋ก๋ฉ ์ํ๋ฅผ ๊ด๋ฆฌํ ์ ์์ต๋๋ค.
const ParentComponent = () => {
// ...
return (
<div>
<h2>๋ถ๋ชจ ์ปดํฌ๋ํธ</h2>
<ChildComponent1 />
<ChildComponent2 />
</div>
);
};
const ChildComponent1 = () => {
return (
<Suspense fallback={<p>์์ 1 ๋ก๋ฉ ์ค...</p>}>
<AsyncChild1 />
</Suspense>
);
};
const ChildComponent2 = () => {
return (
<Suspense fallback={<p>์์ 2 ๋ก๋ฉ ์ค...</p>}>
<AsyncChild2 />
</Suspense>
);
};
const AsyncChild1 = () => {
const data = useAsyncData('child1'); // ๋น๋๊ธฐ ๋ฐ์ดํฐ ๊ฐ์ ธ์ค๊ธฐ๋ฅผ ์ํ ์ปค์คํ
ํ
return <p>์์ 1์ ๋ฐ์ดํฐ: {data}</p>;
};
const AsyncChild2 = () => {
const data = useAsyncData('child2'); // ๋น๋๊ธฐ ๋ฐ์ดํฐ ๊ฐ์ ธ์ค๊ธฐ๋ฅผ ์ํ ์ปค์คํ
ํ
return <p>์์ 2์ ๋ฐ์ดํฐ: {data}</p>;
};
const useAsyncData = (key) => {
const [data, setData] = React.useState(null);
React.useEffect(() => {
let didCancel = false;
const fetchData = async () => {
// ๋ฐ์ดํฐ ๊ฐ์ ธ์ค๊ธฐ ์ง์ฐ ์๋ฎฌ๋ ์ด์
await new Promise(resolve => setTimeout(resolve, 1000));
if (!didCancel) {
setData(`${key}๋ฅผ ์ํ ๋ฐ์ดํฐ`);
}
};
fetchData();
return () => {
didCancel = true;
};
}, [key]);
if (data === null) {
throw new Promise(resolve => setTimeout(resolve, 1000)); // ๋์ค์ ํด๊ฒฐ๋ ํ๋ก๋ฏธ์ค ์๋ฎฌ๋ ์ด์
}
return data;
};
export default ParentComponent;
์ฅ์ : ๊ตฌํ์ด ๊ฐ๋จํ๋ฉฐ, ๊ฐ ์ปดํฌ๋ํธ๊ฐ ์์ฒด ๋ก๋ฉ ์ํ๋ฅผ ์ฒ๋ฆฌํฉ๋๋ค. ๋จ์ : ์ฌ๋ฌ ๋ก๋ฉ ํ์๊ธฐ๊ฐ ๋ค๋ฅธ ์๊ฐ์ ๋ํ๋ ์ฌ์ฉ์ ๊ฒฝํ์ ์ด์ํ๊ฒ ๋ง๋ค ์ ์์ต๋๋ค. ๋ก๋ฉ ํ์๊ธฐ์ "ํญํฌ์" ํจ๊ณผ๋ ์๊ฐ์ ์ผ๋ก ๋งค๋ ฅ์ ์ด์ง ์์ ์ ์์ต๋๋ค.
2. ์ต์์ ๋ ๋ฒจ์ ๊ณต์ Suspense ๊ฒฝ๊ณ
๋ ๋ค๋ฅธ ์ ๊ทผ ๋ฐฉ์์ ์ ์ฒด ์ปดํฌ๋ํธ ํธ๋ฆฌ๋ฅผ ์ต์์ ๋ ๋ฒจ์์ ๋จ์ผ <Suspense>
๊ฒฝ๊ณ๋ก ๊ฐ์ธ๋ ๊ฒ์
๋๋ค. ์ด๋ ๊ฒ ํ๋ฉด ๋ชจ๋ ๋น๋๊ธฐ ๋ฐ์ดํฐ๊ฐ ๋ก๋๋ ๋๊น์ง ์ ์ฒด UI๊ฐ ๊ธฐ๋ค๋ ธ๋ค๊ฐ ๋ ๋๋ง๋ฉ๋๋ค.
const App = () => {
return (
<Suspense fallback={<p>์ฑ ๋ก๋ฉ ์ค...</p>}>
<ParentComponent />
</Suspense>
);
};
์ฅ์ : ๋ชจ๋ ๋ฐ์ดํฐ๊ฐ ๋ก๋๋ ํ ์ ์ฒด UI๊ฐ ํ ๋ฒ์ ๋ํ๋๋ฏ๋ก ๋ ์ผ๊ด๋ ๋ก๋ฉ ๊ฒฝํ์ ์ ๊ณตํฉ๋๋ค. ๋จ์ : ์ผ๋ถ ์ปดํฌ๋ํธ๊ฐ ๋ฐ์ดํฐ๋ฅผ ๋ก๋ํ๋ ๋ฐ ์๋นํ ์๊ฐ์ด ๊ฑธ๋ฆฌ๋ ๊ฒฝ์ฐ, ์ฌ์ฉ์๊ฐ ๋ฌด์ธ๊ฐ๋ฅผ ๋ณด๊ธฐ๊น์ง ์ค๋ ์๊ฐ์ ๊ธฐ๋ค๋ ค์ผ ํ ์ ์์ต๋๋ค. ์ด๋ ๋ชจ๋ ์๋๋ฆฌ์ค์ ์ด์์ ์ด์ง ์์ '์ ๋ถ ์๋๋ฉด ์ ๋ฌด' ๋ฐฉ์์ ๋๋ค.
3. ์กฐํ๋ก์ด ๋ก๋ฉ์ ์ํ SuspenseList
<SuspenseList>
๋ Suspense ๊ฒฝ๊ณ๊ฐ ๋ํ๋๋ ์์๋ฅผ ์กฐ์ ํ ์ ์๋ ์ปดํฌ๋ํธ์
๋๋ค. ์ด๋ฅผ ํตํด ๋ก๋ฉ ์ํ ํ์๋ฅผ ์ ์ดํ์ฌ ํญํฌ์ ํจ๊ณผ๋ฅผ ๋ฐฉ์งํ๊ณ ๋ ๋ถ๋๋ฌ์ด ์๊ฐ์ ์ ํ์ ๋ง๋ค ์ ์์ต๋๋ค.
<SuspenseList>
์๋ ๋ ๊ฐ์ง ์ฃผ์ props๊ฐ ์์ต๋๋ค:
* `revealOrder`: <SuspenseList>
์ ์์๋ค์ด ๋ํ๋๋ ์์๋ฅผ ์ ์ดํฉ๋๋ค. `'forwards'`, `'backwards'`, ๋๋ `'together'`๊ฐ ๋ ์ ์์ต๋๋ค.
* `tail`: ์ผ๋ถ ํญ๋ชฉ์ ์ค๋น๋์์ง๋ง ์ ๋ถ๋ ์๋ ๋, ์์ง ๋ํ๋์ง ์์ ๋๋จธ์ง ํญ๋ชฉ์ ์ด๋ป๊ฒ ์ฒ๋ฆฌํ ์ง ์ ์ดํฉ๋๋ค. `'collapsed'` ๋๋ `'suspended'`๊ฐ ๋ ์ ์์ต๋๋ค.
import { unstable_SuspenseList as SuspenseList } from 'react';
const ParentComponent = () => {
return (
<div>
<h2>๋ถ๋ชจ ์ปดํฌ๋ํธ</h2>
<SuspenseList revealOrder="forwards" tail="suspended">
<Suspense fallback={<p>์์ 1 ๋ก๋ฉ ์ค...</p>}>
<ChildComponent1 />
</Suspense>
<Suspense fallback={<p>์์ 2 ๋ก๋ฉ ์ค...</p>}>
<ChildComponent2 />
</Suspense>
</SuspenseList>
</div>
);
};
์ด ์์ ์์, `revealOrder="forwards"` prop์ ChildComponent1
์ด ChildComponent2
๋ณด๋ค ๋จผ์ ๋ํ๋๋๋ก ๋ณด์ฅํฉ๋๋ค. `tail="suspended"` prop์ ChildComponent1
์ด ์์ ํ ๋ก๋๋ ๋๊น์ง ChildComponent2
์ ๋ก๋ฉ ํ์๊ธฐ๊ฐ ๊ณ์ ๋ณด์ด๋๋ก ํฉ๋๋ค.
์ฅ์ : ๋ก๋ฉ ์ํ๊ฐ ๋ํ๋๋ ์์๋ฅผ ์ธ๋ฐํ๊ฒ ์ ์ดํ์ฌ ๋ ์์ธก ๊ฐ๋ฅํ๊ณ ์๊ฐ์ ์ผ๋ก ๋งค๋ ฅ์ ์ธ ๋ก๋ฉ ๊ฒฝํ์ ์ ๊ณตํฉ๋๋ค. ํญํฌ์ ํจ๊ณผ๋ฅผ ๋ฐฉ์งํฉ๋๋ค.
๋จ์ : <SuspenseList>
์ ๊ทธ props์ ๋ํ ๋ ๊น์ ์ดํด๊ฐ ํ์ํฉ๋๋ค. ๊ฐ๋ณ Suspense ๊ฒฝ๊ณ๋ณด๋ค ์ค์ ์ด ๋ ๋ณต์กํ ์ ์์ต๋๋ค.
4. Suspense์ ์ปค์คํ ๋ก๋ฉ ํ์๊ธฐ ๊ฒฐํฉ
<Suspense>
๊ฐ ์ ๊ณตํ๋ ๊ธฐ๋ณธ fallback UI ๋์ , ์ฌ์ฉ์์๊ฒ ๋ ๋ง์ ์๊ฐ์ ๋งฅ๋ฝ์ ์ ๊ณตํ๋ ์ปค์คํ
๋ก๋ฉ ํ์๊ธฐ๋ฅผ ๋ง๋ค ์ ์์ต๋๋ค. ์๋ฅผ ๋ค์ด, ๋ก๋๋๋ ์ปดํฌ๋ํธ์ ๋ ์ด์์์ ๋ชจ๋ฐฉํ ์ค์ผ๋ ํค ๋ก๋ฉ ์ ๋๋ฉ์ด์
์ ํ์ํ ์ ์์ต๋๋ค. ์ด๋ ์ธ์ง ์ฑ๋ฅ๊ณผ ์ฌ์ฉ์ ๊ฒฝํ์ ํฌ๊ฒ ํฅ์์ํฌ ์ ์์ต๋๋ค.
const ChildComponent1 = () => {
return (
<Suspense fallback={<SkeletonLoader />}>
<AsyncChild1 />
</Suspense>
);
};
const SkeletonLoader = () => {
return (
<div className="skeleton-loader">
<div className="skeleton-line"></div>
<div className="skeleton-line"></div>
<div className="skeleton-line"></div>
</div>
);
};
(.skeleton-loader์ .skeleton-line์ ๋ํ CSS ์คํ์ผ๋ง์ ์ ๋๋ฉ์ด์ ํจ๊ณผ๋ฅผ ๋ง๋ค๊ธฐ ์ํด ๋ณ๋๋ก ์ ์ํด์ผ ํฉ๋๋ค.)
์ฅ์ : ๋ ๋งค๋ ฅ์ ์ด๊ณ ์ ์ตํ ๋ก๋ฉ ๊ฒฝํ์ ๋ง๋ญ๋๋ค. ์ธ์ง ์ฑ๋ฅ์ ํฌ๊ฒ ํฅ์์ํฌ ์ ์์ต๋๋ค. ๋จ์ : ๊ฐ๋จํ ๋ก๋ฉ ํ์๊ธฐ๋ณด๋ค ๊ตฌํํ๋ ๋ฐ ๋ ๋ง์ ๋ ธ๋ ฅ์ด ํ์ํฉ๋๋ค.
5. Suspense์ ํตํฉ๋ ๋ฐ์ดํฐ ๊ฐ์ ธ์ค๊ธฐ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ํ์ฉ
Relay๋ SWR(Stale-While-Revalidate)๊ณผ ๊ฐ์ ์ผ๋ถ ๋ฐ์ดํฐ ๊ฐ์ ธ์ค๊ธฐ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ Suspense์ ์ํํ๊ฒ ์๋ํ๋๋ก ์ค๊ณ๋์์ต๋๋ค. ์ด๋ฌํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ค์ ๋ฐ์ดํฐ๊ฐ ๋ก๋๋๋ ๋์ ์ปดํฌ๋ํธ๋ฅผ ์ผ์ ์ค๋จํ๋ ๋ด์ฅ ๋ฉ์ปค๋์ฆ์ ์ ๊ณตํ์ฌ ๋ก๋ฉ ์ํ ๊ด๋ฆฌ๋ฅผ ๋ ์ฝ๊ฒ ๋ง๋ญ๋๋ค.
๋ค์์ SWR์ ์ฌ์ฉํ ์์ ๋๋ค:
import useSWR from 'swr'
const AsyncChild1 = () => {
const { data, error } = useSWR('/api/data', fetcher)
if (error) return <div>๋ก๋ ์คํจ</div>
if (!data) return <div>๋ก๋ฉ ์ค...</div> // SWR์ด ๋ด๋ถ์ ์ผ๋ก suspense๋ฅผ ์ฒ๋ฆฌํฉ๋๋ค
return <div>{data.name}</div>
}
const fetcher = (...args) => fetch(...args).then(res => res.json())
SWR์ ๋ฐ์ดํฐ ๋ก๋ฉ ์ํ์ ๋ฐ๋ผ suspense ๋์์ ์๋์ผ๋ก ์ฒ๋ฆฌํฉ๋๋ค. ๋ฐ์ดํฐ๊ฐ ์์ง ์ฌ์ฉ ๊ฐ๋ฅํ์ง ์์ผ๋ฉด ์ปดํฌ๋ํธ๋ ์ผ์ ์ค๋จ๋๊ณ , <Suspense>
fallback์ด ํ์๋ฉ๋๋ค.
์ฅ์ : ๋ฐ์ดํฐ ๊ฐ์ ธ์ค๊ธฐ ๋ฐ ๋ก๋ฉ ์ํ ๊ด๋ฆฌ๋ฅผ ๋จ์ํํฉ๋๋ค. ์ข ์ข ์ฑ๋ฅ ํฅ์์ ์ํ ์บ์ฑ ๋ฐ ์ฌ๊ฒ์ฆ ์ ๋ต์ ์ ๊ณตํฉ๋๋ค. ๋จ์ : ํน์ ๋ฐ์ดํฐ ๊ฐ์ ธ์ค๊ธฐ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฑํํด์ผ ํฉ๋๋ค. ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ๊ด๋ จ๋ ํ์ต ๊ณก์ ์ด ์์ ์ ์์ต๋๋ค.
๊ณ ๊ธ ๊ณ ๋ ค ์ฌํญ
์ค๋ฅ ๊ฒฝ๊ณ(Error Boundaries)๋ฅผ ์ฌ์ฉํ ์ค๋ฅ ์ฒ๋ฆฌ
Suspense๋ ๋ก๋ฉ ์ํ๋ฅผ ์ฒ๋ฆฌํ์ง๋ง, ๋ฐ์ดํฐ ๊ฐ์ ธ์ค๊ธฐ ์ค์ ๋ฐ์ํ ์ ์๋ ์ค๋ฅ๋ ์ฒ๋ฆฌํ์ง ์์ต๋๋ค. ์ค๋ฅ ์ฒ๋ฆฌ๋ฅผ ์ํด์๋ ์ค๋ฅ ๊ฒฝ๊ณ(Error Boundaries)๋ฅผ ์ฌ์ฉํด์ผ ํฉ๋๋ค. ์ค๋ฅ ๊ฒฝ๊ณ๋ ์์ ์ปดํฌ๋ํธ ํธ๋ฆฌ ์ด๋์์๋ JavaScript ์ค๋ฅ๋ฅผ ํฌ์ฐฉํ๊ณ , ํด๋น ์ค๋ฅ๋ฅผ ๊ธฐ๋กํ๋ฉฐ, ๋์ฒด UI๋ฅผ ํ์ํ๋ React ์ปดํฌ๋ํธ์ ๋๋ค.
class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false };
}
static getDerivedStateFromError(error) {
// ๋ค์ ๋ ๋๋ง์์ ๋์ฒด UI๋ฅผ ํ์ํ๋๋ก ์ํ๋ฅผ ์
๋ฐ์ดํธํฉ๋๋ค.
return { hasError: true };
}
componentDidCatch(error, errorInfo) {
// ์ค๋ฅ ๋ณด๊ณ ์๋น์ค์ ์ค๋ฅ๋ฅผ ๊ธฐ๋กํ ์๋ ์์ต๋๋ค
console.error(error, errorInfo);
}
render() {
if (this.state.hasError) {
// ์ด๋ค ์ปค์คํ
๋์ฒด UI๋ ๋ ๋๋งํ ์ ์์ต๋๋ค
return <h1>๋ฌธ์ ๊ฐ ๋ฐ์ํ์ต๋๋ค.</h1>;
}
return this.props.children;
}
}
const ParentComponent = () => {
return (
<ErrorBoundary>
<Suspense fallback={<p>๋ก๋ฉ ์ค...</p>}>
<ChildComponent />
</Suspense>
</ErrorBoundary>
);
};
<Suspense>
๊ฒฝ๊ณ๋ฅผ <ErrorBoundary>
๋ก ๊ฐ์ธ ๋ฐ์ดํฐ ๊ฐ์ ธ์ค๊ธฐ ์ค ๋ฐ์ํ ์ ์๋ ๋ชจ๋ ์ค๋ฅ๋ฅผ ์ฒ๋ฆฌํ์ธ์.
์ฑ๋ฅ ์ต์ ํ
Suspense๊ฐ ์ฌ์ฉ์ ๊ฒฝํ์ ๊ฐ์ ํ์ง๋ง, ์ฑ๋ฅ ๋ณ๋ชฉ ํ์์ ํผํ๊ธฐ ์ํด ๋ฐ์ดํฐ ๊ฐ์ ธ์ค๊ธฐ ๋ฐ ์ปดํฌ๋ํธ ๋ ๋๋ง์ ์ต์ ํํ๋ ๊ฒ์ด ์ค์ํฉ๋๋ค. ๋ค์์ ๊ณ ๋ คํ์ธ์:
- ๋ฉ๋ชจ์ด์ ์ด์
:
React.memo
๋ฅผ ์ฌ์ฉํ์ฌ ๋์ผํ props๋ฅผ ๋ฐ๋ ์ปดํฌ๋ํธ์ ๋ถํ์ํ ์ฌ๋ ๋๋ง์ ๋ฐฉ์งํฉ๋๋ค. - ์ฝ๋ ๋ถํ :
React.lazy
๋ฅผ ์ฌ์ฉํ์ฌ ์ฝ๋๋ฅผ ๋ ์์ ์ฒญํฌ๋ก ๋ถํ ํ์ฌ ์ด๊ธฐ ๋ก๋ ์๊ฐ์ ์ค์ ๋๋ค. - ์บ์ฑ: ์ค๋ณต๋ ๋ฐ์ดํฐ ๊ฐ์ ธ์ค๊ธฐ๋ฅผ ํผํ๊ธฐ ์ํด ์บ์ฑ ์ ๋ต์ ๊ตฌํํฉ๋๋ค.
- ๋๋ฐ์ด์ฑ ๋ฐ ์ค๋กํ๋ง: API ํธ์ถ ๋น๋๋ฅผ ์ ํํ๊ธฐ ์ํด ๋๋ฐ์ด์ฑ ๋ฐ ์ค๋กํ๋ง ๊ธฐ์ ์ ์ฌ์ฉํฉ๋๋ค.
์๋ฒ ์ฌ์ด๋ ๋ ๋๋ง (SSR)
Suspense๋ Next.js๋ Remix์ ๊ฐ์ ์๋ฒ ์ฌ์ด๋ ๋ ๋๋ง(SSR) ํ๋ ์์ํฌ์ ํจ๊ป ์ฌ์ฉํ ์๋ ์์ต๋๋ค. ๊ทธ๋ฌ๋ Suspense๋ฅผ ์ฌ์ฉํ SSR์ ๋ฐ์ดํฐ ํ์ด๋๋ ์ด์ ๊ณผ ๊ด๋ จ๋ ๋ณต์ก์ฑ์ ์ ๋ฐํ ์ ์์ผ๋ฏ๋ก ์ ์คํ ๊ณ ๋ ค๊ฐ ํ์ํฉ๋๋ค. ๋ถ์ผ์น๋ฅผ ํผํ๊ธฐ ์ํด ์๋ฒ์์ ๊ฐ์ ธ์จ ๋ฐ์ดํฐ๊ฐ ํด๋ผ์ด์ธํธ์์ ์ฌ๋ฐ๋ฅด๊ฒ ์ง๋ ฌํ๋๊ณ ํ์ด๋๋ ์ด์ ๋๋์ง ํ์ธํ๋ ๊ฒ์ด ์ค์ํฉ๋๋ค. SSR ํ๋ ์์ํฌ๋ ๋ณดํต SSR๊ณผ ํจ๊ป Suspense๋ฅผ ๊ด๋ฆฌํ๊ธฐ ์ํ ํฌํผ์ ๋ชจ๋ฒ ์ฌ๋ก๋ฅผ ์ ๊ณตํฉ๋๋ค.
์ค์ฉ์ ์ธ ์์ ๋ฐ ์ฌ์ฉ ์ฌ๋ก
์ค์ ์ ํ๋ฆฌ์ผ์ด์ ์์ Suspense๋ฅผ ์ด๋ป๊ฒ ์ฌ์ฉํ ์ ์๋์ง ๋ช ๊ฐ์ง ์ค์ฉ์ ์ธ ์์ ๋ฅผ ์ดํด๋ณด๊ฒ ์ต๋๋ค:
1. ์ ์์๊ฑฐ๋ ์ํ ํ์ด์ง
์ ์์๊ฑฐ๋ ์ํ ํ์ด์ง์์๋ ์ํ ์์ธ ์ ๋ณด, ๋ฆฌ๋ทฐ, ๊ด๋ จ ์ํ ๋ฑ ๋น๋๊ธฐ์ ์ผ๋ก ๋ฐ์ดํฐ๋ฅผ ๋ก๋ํ๋ ์ฌ๋ฌ ์น์ ์ด ์์ ์ ์์ต๋๋ค. Suspense๋ฅผ ์ฌ์ฉํ์ฌ ๋ฐ์ดํฐ๊ฐ ๋ก๋๋๋ ๋์ ๊ฐ ์น์ ์ ๋ํ ๋ก๋ฉ ํ์๊ธฐ๋ฅผ ํ์ํ ์ ์์ต๋๋ค.
2. ์์ ๋ฏธ๋์ด ํผ๋
์์ ๋ฏธ๋์ด ํผ๋์์๋ ๊ฒ์๋ฌผ, ๋๊ธ, ์ฌ์ฉ์ ํ๋กํ ๋ฑ์ด ๋ ๋ฆฝ์ ์ผ๋ก ๋ฐ์ดํฐ๋ฅผ ๋ก๋ํ ์ ์์ต๋๋ค. Suspense๋ฅผ ์ฌ์ฉํ์ฌ ๋ฐ์ดํฐ๊ฐ ๋ก๋๋๋ ๋์ ๊ฐ ๊ฒ์๋ฌผ์ ๋ํ ์ค์ผ๋ ํค ๋ก๋ฉ ์ ๋๋ฉ์ด์ ์ ํ์ํ ์ ์์ต๋๋ค.
3. ๋์๋ณด๋ ์ ํ๋ฆฌ์ผ์ด์
๋์๋ณด๋ ์ ํ๋ฆฌ์ผ์ด์ ์์๋ ์ฐจํธ, ํ ์ด๋ธ, ์ง๋๊ฐ ๋ค๋ฅธ ์์ค์์ ๋ฐ์ดํฐ๋ฅผ ๋ก๋ํ ์ ์์ต๋๋ค. Suspense๋ฅผ ์ฌ์ฉํ์ฌ ๋ฐ์ดํฐ๊ฐ ๋ก๋๋๋ ๋์ ๊ฐ ์ฐจํธ, ํ ์ด๋ธ ๋๋ ์ง๋์ ๋ํ ๋ก๋ฉ ํ์๊ธฐ๋ฅผ ํ์ํ ์ ์์ต๋๋ค.
๊ธ๋ก๋ฒ ๋์๋ณด๋ ์ ํ๋ฆฌ์ผ์ด์ ์ ๊ฒฝ์ฐ ๋ค์์ ๊ณ ๋ คํ์ธ์:
- ์๊ฐ๋: ์ฌ์ฉ์์ ํ์ง ์๊ฐ๋์ ๋ง์ถฐ ๋ฐ์ดํฐ๋ฅผ ํ์ํฉ๋๋ค.
- ํตํ: ์ฌ์ฉ์์ ํ์ง ํตํ๋ก ๊ธ์ก์ ํ์ํฉ๋๋ค.
- ์ธ์ด: ๋์๋ณด๋ ์ธํฐํ์ด์ค์ ๋ค๊ตญ์ด ์ง์์ ์ ๊ณตํฉ๋๋ค.
- ์ง์ญ๋ณ ๋ฐ์ดํฐ: ์ฌ์ฉ์๊ฐ ์์ ์ ์ง์ญ์ด๋ ๊ตญ๊ฐ์ ๋ฐ๋ผ ๋ฐ์ดํฐ๋ฅผ ํํฐ๋งํ๊ณ ๋ณผ ์ ์๋๋ก ํฉ๋๋ค.
๊ฒฐ๋ก
React Suspense๋ React ์ ํ๋ฆฌ์ผ์ด์ ์์ ๋น๋๊ธฐ ๋ฐ์ดํฐ ๊ฐ์ ธ์ค๊ธฐ ๋ฐ ๋ก๋ฉ ์ํ๋ฅผ ๊ด๋ฆฌํ๋ ๊ฐ๋ ฅํ ๋๊ตฌ์ ๋๋ค. ์ค์ฒฉ๋ ๋ก๋ฉ ๊ด๋ฆฌ์ ๋ํ ๋ค์ํ ์ ๋ต์ ์ดํดํจ์ผ๋ก์จ ๋ณต์กํ ์ปดํฌ๋ํธ ํธ๋ฆฌ์์๋ ๋ ๋ถ๋๋ฝ๊ณ ๋งค๋ ฅ์ ์ธ ์ฌ์ฉ์ ๊ฒฝํ์ ๋ง๋ค ์ ์์ต๋๋ค. ํ๋ก๋์ ์ ํ๋ฆฌ์ผ์ด์ ์์ Suspense๋ฅผ ์ฌ์ฉํ ๋๋ ์ค๋ฅ ์ฒ๋ฆฌ, ์ฑ๋ฅ ์ต์ ํ, ์๋ฒ ์ฌ์ด๋ ๋ ๋๋ง์ ๊ณ ๋ คํ๋ ๊ฒ์ ์์ง ๋ง์ญ์์ค. ๋น๋๊ธฐ ์์ ์ ๋ง์ ์ ํ๋ฆฌ์ผ์ด์ ์์ ํํ๋ฉฐ, React Suspense๋ฅผ ์ฌ์ฉํ๋ฉด ์ด๋ฅผ ๊น๋ํ๊ฒ ์ฒ๋ฆฌํ ์ ์์ต๋๋ค.