ํจ์จ์ ์ด๊ณ ์ฑ๋ฅ ์ข์ ์ ํ๋ฆฌ์ผ์ด์ ์ ์ํ React Suspense, ๋ฆฌ์์ค ์์กด์ฑ ๊ทธ๋ํ, ๋ฐ์ดํฐ ๋ก๋ฉ ์ค์ผ์คํธ๋ ์ด์ ์ ํ์ํด ๋ณด์ธ์. ๋ชจ๋ฒ ์ฌ๋ก์ ๊ณ ๊ธ ๊ธฐ์ ์ ๋ฐฐ์๋ณด์ธ์.
React Suspense ๋ฆฌ์์ค ์์กด์ฑ ๊ทธ๋ํ: ๋ฐ์ดํฐ ๋ก๋ฉ ์ค์ผ์คํธ๋ ์ด์
React 16.6์์ ๋์ ๋๊ณ ํ์ ๋ฒ์ ์์ ๋์ฑ ๊ฐ์ ๋ React Suspense๋ React ์ ํ๋ฆฌ์ผ์ด์ ์์ ๋น๋๊ธฐ ๋ฐ์ดํฐ ๋ก๋ฉ์ ์ฒ๋ฆฌํ๋ ๋ฐฉ์์ ํ์ ์ ๊ฐ์ ธ์์ต๋๋ค. ์ด ๊ฐ๋ ฅํ ๊ธฐ๋ฅ์ ๋ฆฌ์์ค ์์กด์ฑ ๊ทธ๋ํ์ ๊ฒฐํฉํ์ฌ ๋ฐ์ดํฐ ํ์นญ ๋ฐ UI ๋ ๋๋ง์ ๋ํด ๋ณด๋ค ์ ์ธ์ ์ด๊ณ ํจ์จ์ ์ธ ์ ๊ทผ ๋ฐฉ์์ ๊ฐ๋ฅํ๊ฒ ํฉ๋๋ค. ์ด ๋ธ๋ก๊ทธ ๊ฒ์๋ฌผ์์๋ React Suspense, ๋ฆฌ์์ค ์์กด์ฑ ๊ทธ๋ํ, ๋ฐ์ดํฐ ๋ก๋ฉ ์ค์ผ์คํธ๋ ์ด์ ์ ๊ฐ๋ ์ ์ฌ๋ ์๊ฒ ๋ค๋ฃจ์ด, ์ฑ๋ฅ ์ข๊ณ ์ฌ์ฉ์ ์นํ์ ์ธ ์ ํ๋ฆฌ์ผ์ด์ ์ ๊ตฌ์ถํ๋ ๋ฐ ํ์ํ ์ง์๊ณผ ๋๊ตฌ๋ฅผ ์ ๊ณตํฉ๋๋ค.
React Suspense ์ดํดํ๊ธฐ
ํต์ฌ์ ์ผ๋ก React Suspense๋ ์ปดํฌ๋ํธ๊ฐ API์์ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ค๋ ๊ฒ๊ณผ ๊ฐ์ ๋น๋๊ธฐ ์์ ์ด ์๋ฃ๋๊ธฐ๋ฅผ ๊ธฐ๋ค๋ฆฌ๋ ๋์ ๋ ๋๋ง์ "์ผ์ ์ค๋จ"ํ ์ ์๊ฒ ํด์ค๋๋ค. ์ ํ๋ฆฌ์ผ์ด์ ๊ณณ๊ณณ์ ํฉ์ด์ ธ ์๋ ๋ก๋ฉ ์คํผ๋๋ฅผ ๋ณด์ฌ์ฃผ๋ ๋์ , Suspense๋ ๋ก๋ฉ ์ํ๋ฅผ ์ฒ๋ฆฌํ๋ ํตํฉ๋๊ณ ์ ์ธ์ ์ธ ๋ฐฉ๋ฒ์ ์ ๊ณตํฉ๋๋ค.
์ฃผ์ ๊ฐ๋ :
- Suspense ๊ฒฝ๊ณ(Boundary): ์ผ์ ์ค๋จ๋ ์ ์๋ ์ปดํฌ๋ํธ๋ฅผ ๊ฐ์ธ๋
<Suspense>์ปดํฌ๋ํธ์ ๋๋ค. ์ด๋fallbackprop์ ๋ฐ์, ๊ฐ์ธ์ง ์ปดํฌ๋ํธ๊ฐ ์ผ์ ์ค๋จ๋ ๋์ ๋ ๋๋งํ UI๋ฅผ ์ง์ ํฉ๋๋ค. - Suspense ํธํ ๋ฐ์ดํฐ ํ์นญ: Suspense์ ํจ๊ป ์๋ํ๋ ค๋ฉด, ์์ธ๋ก ๋์ ธ์ง ์ ์๋ "thenable"(Promise)์ ์ฌ์ฉํ๋ ํน์ ๋ฐฉ์์ผ๋ก ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์์ผ ํฉ๋๋ค. ์ด๋ React์๊ฒ ์ปดํฌ๋ํธ๊ฐ ์ผ์ ์ค๋จ๋์ด์ผ ํจ์ ์๋ฆฌ๋ ์ ํธ์ ๋๋ค.
- ๋์์ฑ ๋ชจ๋(Concurrent Mode): Suspense๋ ๋์์ฑ ๋ชจ๋ ์์ด๋ ์ฌ์ฉํ ์ ์์ง๋ง, ํจ๊ป ์ฌ์ฉํ ๋ ๊ทธ ์ ์ฌ๋ ฅ์ด ์ต๋ํ ๋ฐํ๋ฉ๋๋ค. ๋์์ฑ ๋ชจ๋๋ React๊ฐ UI ์๋ต์ฑ์ ์ ์งํ๊ธฐ ์ํด ๋ ๋๋ง์ ์ค๋จ, ์ผ์ ์ ์ง, ์ฌ๊ฐ ๋๋ ํฌ๊ธฐํ ์ ์๊ฒ ํด์ค๋๋ค.
React Suspense์ ์ฅ์
- ํฅ์๋ ์ฌ์ฉ์ ๊ฒฝํ: ์ผ๊ด๋ ๋ก๋ฉ ํ์๊ธฐ์ ๋ถ๋๋ฌ์ด ์ ํ์ ์ ๋ฐ์ ์ธ ์ฌ์ฉ์ ๊ฒฝํ์ ๊ฐ์ ํฉ๋๋ค. ์ฌ์ฉ์๋ ๊นจ์ง๊ฑฐ๋ ๋ถ์์ ํ UI ๋์ ๋ฐ์ดํฐ๊ฐ ๋ก๋ ์ค์ด๋ผ๋ ๋ช ํํ ํ์๋ฅผ ๋ณด๊ฒ ๋ฉ๋๋ค.
- ์ ์ธ์ ๋ฐ์ดํฐ ํ์นญ: Suspense๋ ๋ฐ์ดํฐ ํ์นญ์ ๋ํ ๋ณด๋ค ์ ์ธ์ ์ธ ์ ๊ทผ ๋ฐฉ์์ ์ฅ๋ คํ์ฌ ์ฝ๋ ๊ฐ๋ ์ฑ๊ณผ ์ ์ง๋ณด์์ฑ์ ๋์ ๋๋ค. ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ค๊ณ ๋ก๋ฉ ์ํ๋ฅผ ๊ด๋ฆฌํ๋ *๋ฐฉ๋ฒ*์ด ์๋, *์ด๋ค* ๋ฐ์ดํฐ๊ฐ ํ์ํ์ง์ ์ง์คํ๊ฒ ๋ฉ๋๋ค.
- ์ฝ๋ ๋ถํ (Code Splitting): Suspense๋ ์ปดํฌ๋ํธ๋ฅผ ์ง์ฐ ๋ก๋ฉ(lazy-load)ํ๋ ๋ฐ ์ฌ์ฉ๋ ์ ์์ด, ์ด๊ธฐ ๋ฒ๋ค ํฌ๊ธฐ๋ฅผ ์ค์ด๊ณ ์ด๊ธฐ ํ์ด์ง ๋ก๋ ์๊ฐ์ ๊ฐ์ ํฉ๋๋ค.
- ๋จ์ํ๋ ์ํ ๊ด๋ฆฌ: Suspense๋ ๋ก๋ฉ ๋ก์ง์ Suspense ๊ฒฝ๊ณ ๋ด์ ์ค์ ์ง์คํํ์ฌ ์ํ ๊ด๋ฆฌ์ ๋ณต์ก์ฑ์ ์ค์ผ ์ ์์ต๋๋ค.
๋ฆฌ์์ค ์์กด์ฑ ๊ทธ๋ํ: ๋ฐ์ดํฐ ํ์นญ ์ค์ผ์คํธ๋ ์ด์
๋ฆฌ์์ค ์์กด์ฑ ๊ทธ๋ํ๋ ์ ํ๋ฆฌ์ผ์ด์ ๋ด์ ๋ค์ํ ๋ฐ์ดํฐ ๋ฆฌ์์ค ๊ฐ์ ์์กด์ฑ์ ์๊ฐํํฉ๋๋ค. ์ด๋ฌํ ์์กด์ฑ์ ์ดํดํ๋ ๊ฒ์ ํจ์จ์ ์ธ ๋ฐ์ดํฐ ๋ก๋ฉ ์ค์ผ์คํธ๋ ์ด์ ์ ๋งค์ฐ ์ค์ํฉ๋๋ค. ์ด๋ค ๋ฆฌ์์ค๊ฐ ๋ค๋ฅธ ๋ฆฌ์์ค์ ์์กดํ๋์ง ํ์ ํจ์ผ๋ก์จ ์ต์ ์ ์์๋ก ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ ์ง์ฐ์ ์ต์ํํ๊ณ ์ฑ๋ฅ์ ํฅ์์ํฌ ์ ์์ต๋๋ค.
๋ฆฌ์์ค ์์กด์ฑ ๊ทธ๋ํ ๋ง๋ค๊ธฐ
๋จผ์ ์ ํ๋ฆฌ์ผ์ด์ ์ ํ์ํ ๋ชจ๋ ๋ฐ์ดํฐ ๋ฆฌ์์ค๋ฅผ ์๋ณํ๋ ๊ฒ๋ถํฐ ์์ํ์ธ์. ์ด๋ API ์๋ํฌ์ธํธ, ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ฟผ๋ฆฌ ๋๋ ๋ก์ปฌ ๋ฐ์ดํฐ ํ์ผ์ผ ์ ์์ต๋๋ค. ๊ทธ๋ฐ ๋ค์ ์ด๋ฌํ ๋ฆฌ์์ค ๊ฐ์ ์์กด์ฑ์ ๋งคํํ์ธ์. ์๋ฅผ ๋ค์ด, ์ฌ์ฉ์ ํ๋กํ ์ปดํฌ๋ํธ๋ ์ฌ์ฉ์ ID์ ์์กดํ ์ ์์ผ๋ฉฐ, ์ด๋ ๋ค์ ์ธ์ฆ ๋ฐ์ดํฐ์ ์์กดํ ์ ์์ต๋๋ค.
์์: ์ ์์๊ฑฐ๋ ์ ํ๋ฆฌ์ผ์ด์
์ ์์๊ฑฐ๋ ์ ํ๋ฆฌ์ผ์ด์ ์ ์๊ฐํด ๋ด ์๋ค. ๋ค์๊ณผ ๊ฐ์ ๋ฆฌ์์ค๊ฐ ์์ ์ ์์ต๋๋ค:
- ์ฌ์ฉ์ ์ธ์ฆ: ์ฌ์ฉ์ ์๊ฒฉ ์ฆ๋ช ์ด ํ์ํฉ๋๋ค.
- ์ํ ๋ชฉ๋ก: ์นดํ ๊ณ ๋ฆฌ ID๊ฐ ํ์ํฉ๋๋ค (๋ด๋น๊ฒ์ด์ ๋ฉ๋ด์์ ์ป์).
- ์ํ ์์ธ ์ ๋ณด: ์ํ ID๊ฐ ํ์ํฉ๋๋ค (์ํ ๋ชฉ๋ก์์ ์ป์).
- ์ฌ์ฉ์ ์ฅ๋ฐ๊ตฌ๋: ์ฌ์ฉ์ ์ธ์ฆ์ด ํ์ํฉ๋๋ค.
- ๋ฐฐ์ก ์ต์ : ์ฌ์ฉ์ ์ฃผ์๊ฐ ํ์ํฉ๋๋ค (์ฌ์ฉ์ ํ๋กํ์์ ์ป์).
์์กด์ฑ ๊ทธ๋ํ๋ ๋ค์๊ณผ ๊ฐ์ด ๋ณด์ผ ๊ฒ์ ๋๋ค:
์ฌ์ฉ์ ์ธ์ฆ --> ์ฌ์ฉ์ ์ฅ๋ฐ๊ตฌ๋, ๋ฐฐ์ก ์ต์ ์ํ ๋ชฉ๋ก --> ์ํ ์์ธ ์ ๋ณด ๋ฐฐ์ก ์ต์ --> ์ฌ์ฉ์ ํ๋กํ (์ฃผ์)
์ด ๊ทธ๋ํ๋ ๋ฐ์ดํฐ๋ฅผ ์ด๋ค ์์๋ก ๊ฐ์ ธ์์ผ ํ๋์ง ์ดํดํ๋ ๋ฐ ๋์์ด ๋ฉ๋๋ค. ์๋ฅผ ๋ค์ด, ์ฌ์ฉ์๊ฐ ์ธ์ฆ๋๊ธฐ ์ ๊น์ง๋ ์ฌ์ฉ์ ์ฅ๋ฐ๊ตฌ๋๋ฅผ ๋ก๋ํ ์ ์์ต๋๋ค.
๋ฆฌ์์ค ์์กด์ฑ ๊ทธ๋ํ ์ฌ์ฉ์ ์ด์
- ์ต์ ํ๋ ๋ฐ์ดํฐ ํ์นญ: ์์กด์ฑ์ ์ดํดํจ์ผ๋ก์จ ๊ฐ๋ฅํ ๋๋ง๋ค ๋ฐ์ดํฐ๋ฅผ ๋ณ๋ ฌ๋ก ๊ฐ์ ธ์ ์ ์ฒด ๋ก๋ฉ ์๊ฐ์ ์ค์ผ ์ ์์ต๋๋ค.
- ๊ฐ์ ๋ ์ค๋ฅ ์ฒ๋ฆฌ: ์์กด์ฑ์ ๋ํ ๋ช ํํ ์ดํด๋ ์ค๋ฅ๋ฅผ ๋ ์ฐ์ํ๊ฒ ์ฒ๋ฆฌํ ์ ์๊ฒ ํด์ค๋๋ค. ์ค์ํ ๋ฆฌ์์ค ๋ก๋์ ์คํจํ๋ฉด ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ค๋ฅธ ๋ถ๋ถ์ ์ํฅ์ ์ฃผ์ง ์๊ณ ์ ์ ํ ์ค๋ฅ ๋ฉ์์ง๋ฅผ ํ์ํ ์ ์์ต๋๋ค.
- ์ฑ๋ฅ ํฅ์: ํจ์จ์ ์ธ ๋ฐ์ดํฐ ๋ก๋ฉ์ ๋ ๋ฐ์์ฑ์ด ์ข๊ณ ์ฑ๋ฅ์ด ๋ฐ์ด๋ ์ ํ๋ฆฌ์ผ์ด์ ์ผ๋ก ์ด์ด์ง๋๋ค.
- ๋จ์ํ๋ ๋๋ฒ๊น : ๋ฌธ์ ๊ฐ ๋ฐ์ํ์ ๋ ์์กด์ฑ ๊ทธ๋ํ๋ ๊ทผ๋ณธ ์์ธ์ ์ ์ํ๊ฒ ํ์ ํ๋ ๋ฐ ๋์์ด ๋ ์ ์์ต๋๋ค.
Suspense์ ๋ฆฌ์์ค ์์กด์ฑ ๊ทธ๋ํ๋ฅผ ์ด์ฉํ ๋ฐ์ดํฐ ๋ก๋ฉ ์ค์ผ์คํธ๋ ์ด์
React Suspense๋ฅผ ๋ฆฌ์์ค ์์กด์ฑ ๊ทธ๋ํ์ ๊ฒฐํฉํ๋ฉด ์ ์ธ์ ์ด๊ณ ํจ์จ์ ์ธ ๋ฐฉ์์ผ๋ก ๋ฐ์ดํฐ ๋ก๋ฉ์ ์ค์ผ์คํธ๋ ์ด์ ํ ์ ์์ต๋๋ค. ๋ชฉํ๋ ์ต์ ์ ์์๋ก ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ ์ง์ฐ์ ์ต์ํํ๊ณ ์ํํ ์ฌ์ฉ์ ๊ฒฝํ์ ์ ๊ณตํ๋ ๊ฒ์ ๋๋ค.
๋ฐ์ดํฐ ๋ก๋ฉ ์ค์ผ์คํธ๋ ์ด์ ๋จ๊ณ
- ๋ฐ์ดํฐ ๋ฆฌ์์ค ์ ์: ์ ํ๋ฆฌ์ผ์ด์ ์ ํ์ํ ๋ชจ๋ ๋ฐ์ดํฐ ๋ฆฌ์์ค๋ฅผ ์๋ณํฉ๋๋ค.
- ๋ฆฌ์์ค ์์กด์ฑ ๊ทธ๋ํ ์์ฑ: ์ด๋ฌํ ๋ฆฌ์์ค ๊ฐ์ ์์กด์ฑ์ ๋งคํํฉ๋๋ค.
- Suspense ํธํ ๋ฐ์ดํฐ ํ์นญ ๊ตฌํ:
swr๋react-query์ ๊ฐ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํ๊ฑฐ๋ (๋๋ ์ง์ ๊ตฌํํ์ฌ) Suspense์ ํธํ๋๋ ๋ฐฉ์์ผ๋ก ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ต๋๋ค. ์ด๋ฌํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ค์ Promise๋ฅผ ์์ธ๋ก ๋์ง๊ธฐ ์ํ "thenable" ์๊ตฌ ์ฌํญ์ ์ฒ๋ฆฌํฉ๋๋ค. - ์ปดํฌ๋ํธ๋ฅผ Suspense ๊ฒฝ๊ณ๋ก ๊ฐ์ธ๊ธฐ: ๋น๋๊ธฐ ๋ฐ์ดํฐ์ ์์กดํ๋ ์ปดํฌ๋ํธ๋ฅผ
<Suspense>์ปดํฌ๋ํธ๋ก ๊ฐ์ธ๊ณ , ๋ก๋ฉ ์ํ๋ฅผ ์ํ fallback UI๋ฅผ ์ ๊ณตํฉ๋๋ค. - ๋ฐ์ดํฐ ํ์นญ ์์ ์ต์ ํ: ๋ฆฌ์์ค ์์กด์ฑ ๊ทธ๋ํ๋ฅผ ์ฌ์ฉํ์ฌ ๋ฐ์ดํฐ ํ์นญ์ ์ํ ์ต์ ์ ์์๋ฅผ ๊ฒฐ์ ํฉ๋๋ค. ๋ ๋ฆฝ์ ์ธ ๋ฆฌ์์ค๋ ๋ณ๋ ฌ๋ก ๊ฐ์ ธ์ต๋๋ค.
- ์ฐ์ํ ์ค๋ฅ ์ฒ๋ฆฌ: ์ค๋ฅ ๊ฒฝ๊ณ(error boundary)๋ฅผ ๊ตฌํํ์ฌ ๋ฐ์ดํฐ ํ์นญ ์ค ๋ฐ์ํ๋ ์ค๋ฅ๋ฅผ ํฌ์ฐฉํ๊ณ ์ ์ ํ ์ค๋ฅ ๋ฉ์์ง๋ฅผ ํ์ํฉ๋๋ค.
์์: ๊ฒ์๋ฌผ์ด ์๋ ์ฌ์ฉ์ ํ๋กํ
์ฌ์ฉ์ ์ ๋ณด์ ๊ทธ๋ค์ ๊ฒ์๋ฌผ ๋ชฉ๋ก์ ํ์ํ๋ ์ฌ์ฉ์ ํ๋กํ ํ์ด์ง๋ฅผ ์๊ฐํด ๋ด ์๋ค. ๋ค์๊ณผ ๊ฐ์ ๋ฆฌ์์ค๊ฐ ๊ด๋ จ๋ฉ๋๋ค:
- ์ฌ์ฉ์ ํ๋กํ: ์ฌ์ฉ์ ์ธ๋ถ ์ ๋ณด(์ด๋ฆ, ์ด๋ฉ์ผ ๋ฑ)๋ฅผ ๊ฐ์ ธ์ต๋๋ค.
- ์ฌ์ฉ์ ๊ฒ์๋ฌผ: ํด๋น ์ฌ์ฉ์์ ๊ฒ์๋ฌผ ๋ชฉ๋ก์ ๊ฐ์ ธ์ต๋๋ค.
UserPosts ์ปดํฌ๋ํธ๋ UserProfile ์ปดํฌ๋ํธ์ ์์กดํฉ๋๋ค. ๋ค์์ Suspense๋ฅผ ์ฌ์ฉํ์ฌ ์ด๋ฅผ ๊ตฌํํ๋ ๋ฐฉ๋ฒ์
๋๋ค:
import React, { Suspense } from 'react';
import { use } from 'react';
import { fetchUserProfile, fetchUserPosts } from './api';
// Promise๋ฅผ ๋์ง๋ ๋ฐ์ดํฐ ํ์นญ์ ์๋ฎฌ๋ ์ด์
ํ๋ ๊ฐ๋จํ ํจ์
const createResource = (promise) => {
let status = 'pending';
let result;
let suspender = promise.then(
(r) => {
status = 'success';
result = r;
},
(e) => {
status = 'error';
result = e;
}
);
return {
read() {
if (status === 'pending') {
throw suspender;
}
if (status === 'error') {
throw result;
}
return result;
}
};
};
const userProfileResource = createResource(fetchUserProfile(123)); // ์ฌ์ฉ์ ID 123 ๊ฐ์
const userPostsResource = createResource(fetchUserPosts(123));
function UserProfile() {
const profile = userProfileResource.read();
return (
์ฌ์ฉ์ ํ๋กํ
์ด๋ฆ: {profile.name}
์ด๋ฉ์ผ: {profile.email}
);
}
function UserPosts() {
const posts = userPostsResource.read();
return (
์ฌ์ฉ์ ๊ฒ์๋ฌผ
{posts.map(post => (
- {post.title}
))}
);
}
function ProfilePage() {
return (
);
}
export default ProfilePage;
์ด ์์ ์์ fetchUserProfile๊ณผ fetchUserPosts๋ Promise๋ฅผ ๋ฐํํ๋ ๋น๋๊ธฐ ํจ์์
๋๋ค. createResource ํจ์๋ Promise๋ฅผ read ๋ฉ์๋๊ฐ ์๋ Suspense ํธํ ๋ฆฌ์์ค๋ก ๋ณํํฉ๋๋ค. ๋ฐ์ดํฐ๊ฐ ์ฌ์ฉ ๊ฐ๋ฅํด์ง๊ธฐ ์ ์ userProfileResource.read() ๋๋ userPostsResource.read()๊ฐ ํธ์ถ๋๋ฉด, Promise๋ฅผ ๋์ ธ ์ปดํฌ๋ํธ๊ฐ ์ผ์ ์ค๋จ๋๊ฒ ํฉ๋๋ค. ๊ทธ๋ฌ๋ฉด React๋ <Suspense> ๊ฒฝ๊ณ์ ์ง์ ๋ fallback UI๋ฅผ ๋ ๋๋งํฉ๋๋ค.
๋ฐ์ดํฐ ํ์นญ ์์ ์ต์ ํ
์ ์์ ์์ UserProfile๊ณผ UserPosts ์ปดํฌ๋ํธ๋ ๋ณ๋์ <Suspense> ๊ฒฝ๊ณ๋ก ๊ฐ์ธ์ ธ ์์ต๋๋ค. ์ด๋ฅผ ํตํด ๋
๋ฆฝ์ ์ผ๋ก ๋ก๋๋ ์ ์์ต๋๋ค. ๋ง์ฝ UserPosts๊ฐ UserProfile์ ๋ฐ์ดํฐ์ ์์กดํ๋ค๋ฉด, ์ฌ์ฉ์ ํ๋กํ ๋ฐ์ดํฐ๊ฐ ๋จผ์ ๋ก๋๋๋๋ก ๋ฐ์ดํฐ ํ์นญ ๋ก์ง์ ์กฐ์ ํด์ผ ํฉ๋๋ค.
ํ ๊ฐ์ง ์ ๊ทผ๋ฒ์ UserProfile์์ ์ป์ ์ฌ์ฉ์ ID๋ฅผ fetchUserPosts์ ์ ๋ฌํ๋ ๊ฒ์
๋๋ค. ์ด๋ ๊ฒ ํ๋ฉด ์ฌ์ฉ์ ํ๋กํ์ด ๋ก๋๋ ํ์๋ง ๊ฒ์๋ฌผ์ ๊ฐ์ ธ์ค๊ฒ ๋ฉ๋๋ค.
๊ณ ๊ธ ๊ธฐ์ ๋ฐ ๊ณ ๋ ค ์ฌํญ
Suspense๋ฅผ ์ฌ์ฉํ ์๋ฒ ์ฌ์ด๋ ๋ ๋๋ง(SSR)
Suspense๋ ์๋ฒ ์ฌ์ด๋ ๋ ๋๋ง(SSR)๊ณผ ํจ๊ป ์ฌ์ฉํ์ฌ ์ด๊ธฐ ํ์ด์ง ๋ก๋ ์๊ฐ์ ๊ฐ์ ํ ์๋ ์์ต๋๋ค. ๊ทธ๋ฌ๋ SSR๊ณผ Suspense๋ฅผ ํจ๊ป ์ฌ์ฉํ๋ ๊ฒ์ ์ด๊ธฐ ๋ ๋๋ง ์ค์ ์ผ์ ์ค๋จ๋๋ฉด ์ฑ๋ฅ ๋ฌธ์ ๋ฅผ ์ผ์ผํฌ ์ ์์ผ๋ฏ๋ก ์ ์คํ ๊ณ ๋ ค๊ฐ ํ์ํฉ๋๋ค. ์ด๊ธฐ ๋ ๋๋ง ์ ์ ์ค์ํ ๋ฐ์ดํฐ๊ฐ ์ฌ์ฉ ๊ฐ๋ฅํ์ง ํ์ธํ๊ฑฐ๋, ๋ฐ์ดํฐ๊ฐ ์ฌ์ฉ ๊ฐ๋ฅํด์ง์ ๋ฐ๋ผ ํ์ด์ง๋ฅผ ์ ์ง์ ์ผ๋ก ๋ ๋๋งํ๋ ์คํธ๋ฆฌ๋ฐ SSR์ ์ฌ์ฉํ๋ ๊ฒ์ด ์ค์ํฉ๋๋ค.
์ค๋ฅ ๊ฒฝ๊ณ(Error Boundaries)
์ค๋ฅ ๊ฒฝ๊ณ๋ ๋ฐ์ดํฐ ํ์นญ ์ค์ ๋ฐ์ํ๋ ์ค๋ฅ๋ฅผ ์ฒ๋ฆฌํ๋ ๋ฐ ํ์์ ์
๋๋ค. <Suspense> ๊ฒฝ๊ณ๋ฅผ ์ค๋ฅ ๊ฒฝ๊ณ๋ก ๊ฐ์ธ์ ๋์ ธ์ง ๋ชจ๋ ์ค๋ฅ๋ฅผ ํฌ์ฐฉํ๊ณ ์ฌ์ฉ์์๊ฒ ์ ์ ํ ์ค๋ฅ ๋ฉ์์ง๋ฅผ ํ์ํ์ธ์. ์ด๋ ๊ฒ ํ๋ฉด ์ค๋ฅ๊ฐ ์ ์ฒด ์ ํ๋ฆฌ์ผ์ด์
์ ์ค๋จ์ํค๋ ๊ฒ์ ๋ฐฉ์งํ ์ ์์ต๋๋ค.
import React, { Suspense } from 'react';
class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false };
}
static getDerivedStateFromError(error) {
// ๋ค์ ๋ ๋๋ง์์ fallback UI๋ฅผ ํ์ํ๋๋ก ์ํ๋ฅผ ์
๋ฐ์ดํธํฉ๋๋ค.
return { hasError: true };
}
componentDidCatch(error, errorInfo) {
// ์ค๋ฅ ๋ณด๊ณ ์๋น์ค์ ์ค๋ฅ๋ฅผ ๊ธฐ๋กํ ์๋ ์์ต๋๋ค.
console.error(error, errorInfo);
}
render() {
if (this.state.hasError) {
// ์ฌ์ฉ์ ์ ์ fallback UI๋ฅผ ๋ ๋๋งํ ์ ์์ต๋๋ค.
return <h1>๋ฌธ์ ๊ฐ ๋ฐ์ํ์ต๋๋ค.</h1>;
}
return this.props.children;
}
}
function App() {
return (
<ErrorBoundary>
<Suspense fallback={<p>๋ก๋ฉ ์ค...</p>}>
<MyComponent />
</Suspense>
</ErrorBoundary>
);
}
๋ฐ์ดํฐ ํ์นญ ๋ผ์ด๋ธ๋ฌ๋ฆฌ
React Suspense์ ์ํํ๊ฒ ์๋ํ๋๋ก ์ค๊ณ๋ ์ฌ๋ฌ ๋ฐ์ดํฐ ํ์นญ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐ ์์ต๋๋ค. ์ด๋ฌํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ ์บ์ฑ, ์ค๋ณต ์ ๊ฑฐ, ์๋ ์ฌ์๋์ ๊ฐ์ ๊ธฐ๋ฅ์ ์ ๊ณตํ์ฌ ๋ฐ์ดํฐ ํ์นญ์ ๋ ํจ์จ์ ์ด๊ณ ์ ๋ขฐํ ์ ์๊ฒ ๋ง๋ญ๋๋ค. ์ธ๊ธฐ ์๋ ์ต์ ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค:
- SWR: ์๊ฒฉ ๋ฐ์ดํฐ ํ์นญ์ ์ํ ๊ฒฝ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ๋๋ค. Suspense๋ฅผ ๋ด์ฅ ์ง์ํ๋ฉฐ ์บ์ฑ ๋ฐ ์ฌ๊ฒ์ฆ์ ์๋์ผ๋ก ์ฒ๋ฆฌํฉ๋๋ค.
- React Query: ๋ฐฑ๊ทธ๋ผ์ด๋ ์ ๋ฐ์ดํธ, ๋๊ด์ ์ ๋ฐ์ดํธ, ์ข ์ ์ฟผ๋ฆฌ์ ๊ฐ์ ๊ณ ๊ธ ๊ธฐ๋ฅ์ ์ ๊ณตํ๋ ๋ณด๋ค ํฌ๊ด์ ์ธ ๋ฐ์ดํฐ ํ์นญ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ๋๋ค.
- Relay: ๋ฐ์ดํฐ ๊ธฐ๋ฐ React ์ ํ๋ฆฌ์ผ์ด์ ๊ตฌ์ถ์ ์ํ ํ๋ ์์ํฌ์ ๋๋ค. GraphQL์ ์ฌ์ฉํ์ฌ ๋ฐ์ดํฐ๋ฅผ ์ ์ธ์ ์ผ๋ก ๊ฐ์ ธ์ค๊ณ ๊ด๋ฆฌํ๋ ๋ฐฉ๋ฒ์ ์ ๊ณตํฉ๋๋ค.
๊ธ๋ก๋ฒ ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ํ ๊ณ ๋ ค ์ฌํญ
๊ธ๋ก๋ฒ ์ฌ์ฉ์๋ฅผ ์ํ ์ ํ๋ฆฌ์ผ์ด์ ์ ๊ตฌ์ถํ ๋ ๋ฐ์ดํฐ ๋ก๋ฉ ์ค์ผ์คํธ๋ ์ด์ ์ ๊ตฌํํ ๋ ๋ค์ ์์๋ฅผ ๊ณ ๋ คํ์ธ์:
- ๋คํธ์ํฌ ์ง์ฐ ์๊ฐ: ๋คํธ์ํฌ ์ง์ฐ ์๊ฐ์ ์ฌ์ฉ์์ ์์น์ ๋ฐ๋ผ ํฌ๊ฒ ๋ฌ๋ผ์ง ์ ์์ต๋๋ค. ์ง์ฐ ์๊ฐ์ ์ํฅ์ ์ต์ํํ๋๋ก ๋ฐ์ดํฐ ํ์นญ ์ ๋ต์ ์ต์ ํํ์ธ์. ์ฝํ ์ธ ์ ์ก ๋คํธ์ํฌ(CDN)๋ฅผ ์ฌ์ฉํ์ฌ ์ ์ ์์ฐ์ ์ฌ์ฉ์์ ๋ ๊ฐ๊น์ด ๊ณณ์ ์บ์ํ๋ ๊ฒ์ ๊ณ ๋ คํ์ธ์.
- ๋ฐ์ดํฐ ํ์งํ: ๋ฐ์ดํฐ๊ฐ ์ฌ์ฉ์์ ์ ํธ ์ธ์ด ๋ฐ ์ง์ญ์ ๋ง๊ฒ ํ์งํ๋์๋์ง ํ์ธํ์ธ์. ๊ตญ์ ํ(i18n) ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํ์ฌ ํ์งํ๋ฅผ ์ฒ๋ฆฌํ์ธ์.
- ์๊ฐ๋: ๋ ์ง์ ์๊ฐ์ ํ์ํ ๋ ์๊ฐ๋๋ฅผ ์ผ๋์ ๋์ธ์.
moment.js๋date-fns์ ๊ฐ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํ์ฌ ์๊ฐ๋ ๋ณํ์ ์ฒ๋ฆฌํ์ธ์. - ํตํ: ์ฌ์ฉ์์ ํ์ง ํตํ๋ก ํตํ ๊ฐ์ ํ์ํ์ธ์. ํ์ํ ๊ฒฝ์ฐ ํตํ ๋ณํ API๋ฅผ ์ฌ์ฉํ์ฌ ๊ฐ๊ฒฉ์ ๋ณํํ์ธ์.
- API ์๋ํฌ์ธํธ: ์ง์ฐ ์๊ฐ์ ์ต์ํํ๊ธฐ ์ํด ์ฌ์ฉ์์ ์ง๋ฆฌ์ ์ผ๋ก ๊ฐ๊น์ด API ์๋ํฌ์ธํธ๋ฅผ ์ ํํ์ธ์. ๊ฐ๋ฅํ ๊ฒฝ์ฐ ์ง์ญ๋ณ API ์๋ํฌ์ธํธ๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ ๊ณ ๋ คํ์ธ์.
๋ชจ๋ฒ ์ฌ๋ก
- Suspense ๊ฒฝ๊ณ๋ฅผ ์๊ฒ ์ ์งํ์ธ์: ์ ํ๋ฆฌ์ผ์ด์
์ ํฐ ๋ถ๋ถ์ ๋จ์ผ
<Suspense>๊ฒฝ๊ณ๋ก ๊ฐ์ธ์ง ๋ง์ธ์. UI๋ฅผ ๋ ์๊ณ ๊ด๋ฆฌํ๊ธฐ ์ฌ์ด ์ปดํฌ๋ํธ๋ก ๋๋๊ณ ๊ฐ ์ปดํฌ๋ํธ๋ฅผ ์์ฒด Suspense ๊ฒฝ๊ณ๋ก ๊ฐ์ธ์ธ์. - ์๋ฏธ ์๋ Fallback ์ฌ์ฉํ๊ธฐ: ์ฌ์ฉ์์๊ฒ ๋ฐ์ดํฐ๊ฐ ๋ก๋ ์ค์์ ์๋ฆฌ๋ ์๋ฏธ ์๋ fallback UI๋ฅผ ์ ๊ณตํ์ธ์. ์ผ๋ฐ์ ์ธ ๋ก๋ฉ ์คํผ๋ ์ฌ์ฉ์ ํผํ์ธ์. ๋์ ์ต์ข UI์ ์ ์ฌํ ํ๋ ์ด์คํ๋ UI๋ฅผ ํ์ํ์ธ์.
- ๋ฐ์ดํฐ ํ์นญ ์ต์ ํ:
swr๋react-query์ ๊ฐ์ ๋ฐ์ดํฐ ํ์นญ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํ์ฌ ๋ฐ์ดํฐ ํ์นญ์ ์ต์ ํํ์ธ์. ์ด๋ฌํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ ์บ์ฑ, ์ค๋ณต ์ ๊ฑฐ, ์๋ ์ฌ์๋์ ๊ฐ์ ๊ธฐ๋ฅ์ ์ ๊ณตํฉ๋๋ค. - ์ฐ์ํ๊ฒ ์ค๋ฅ ์ฒ๋ฆฌํ๊ธฐ: ์ค๋ฅ ๊ฒฝ๊ณ๋ฅผ ์ฌ์ฉํ์ฌ ๋ฐ์ดํฐ ํ์นญ ์ค ๋ฐ์ํ๋ ์ค๋ฅ๋ฅผ ํฌ์ฐฉํ๊ณ ์ฌ์ฉ์์๊ฒ ์ ์ ํ ์ค๋ฅ ๋ฉ์์ง๋ฅผ ํ์ํ์ธ์.
- ์ฒ ์ ํ๊ฒ ํ ์คํธํ๊ธฐ: ์ ํ๋ฆฌ์ผ์ด์ ์ ์ฒ ์ ํ๊ฒ ํ ์คํธํ์ฌ ๋ฐ์ดํฐ ๋ก๋ฉ์ด ์ฌ๋ฐ๋ฅด๊ฒ ์๋ํ๊ณ ์ค๋ฅ๊ฐ ์ฐ์ํ๊ฒ ์ฒ๋ฆฌ๋๋์ง ํ์ธํ์ธ์.
๊ฒฐ๋ก
React Suspense๋ ๋ฆฌ์์ค ์์กด์ฑ ๊ทธ๋ํ์ ๊ฒฐํฉํ์ฌ ๋ฐ์ดํฐ ๋ก๋ฉ ์ค์ผ์คํธ๋ ์ด์ ์ ๊ฐ๋ ฅํ๊ณ ์ ์ธ์ ์ธ ์ ๊ทผ ๋ฐฉ์์ ์ ๊ณตํฉ๋๋ค. ๋ฐ์ดํฐ ๋ฆฌ์์ค ๊ฐ์ ์์กด์ฑ์ ์ดํดํ๊ณ Suspense ํธํ ๋ฐ์ดํฐ ํ์นญ์ ๊ตฌํํจ์ผ๋ก์จ ์ฑ๋ฅ ์ข๊ณ ์ฌ์ฉ์ ์นํ์ ์ธ ์ ํ๋ฆฌ์ผ์ด์ ์ ๊ตฌ์ถํ ์ ์์ต๋๋ค. ๋ฐ์ดํฐ ํ์นญ ์ ๋ต์ ์ต์ ํํ๊ณ , ์ค๋ฅ๋ฅผ ์ฐ์ํ๊ฒ ์ฒ๋ฆฌํ๋ฉฐ, ๊ธ๋ก๋ฒ ์ฌ์ฉ์๋ฅผ ์ํ ์ํํ ์ฌ์ฉ์ ๊ฒฝํ์ ๋ณด์ฅํ๊ธฐ ์ํด ์ ํ๋ฆฌ์ผ์ด์ ์ ์ฒ ์ ํ ํ ์คํธํ๋ ๊ฒ์ ์์ง ๋ง์ธ์. React๊ฐ ๊ณ์ ๋ฐ์ ํจ์ ๋ฐ๋ผ Suspense๋ ํ๋ ์น ์ ํ๋ฆฌ์ผ์ด์ ๊ตฌ์ถ์ ์์ด ๋์ฑ ํ์์ ์ธ ๋ถ๋ถ์ด ๋ ๊ฒ์ ๋๋ค.