diff --git a/docs/index.md b/docs/index.md index 9c553bc4..9b82c2b4 100644 --- a/docs/index.md +++ b/docs/index.md @@ -10,7 +10,7 @@ hero: link: /stack - theme: brand text: ๐Ÿ“œ ํŠธ๋Ÿฌ๋ธ”์ŠˆํŒ… - link: /trouble + link: /trouble/index.md - theme: brand text: ๐Ÿ—‚๏ธ ํ”„๋กœ์ ํŠธ ํด๋”๊ตฌ์กฐ link: /folder diff --git a/docs/trouble/gradient.md b/docs/trouble/gradient.md new file mode 100644 index 00000000..9b7df281 --- /dev/null +++ b/docs/trouble/gradient.md @@ -0,0 +1,79 @@ +### โœ” ๋ฌธ์ œ ์š”์•ฝ + +### 1. **๋ฌธ์ œ ์ƒํ™ฉ** + +- ๋งค์นญ ์„ฑ์‚ฌ ํ™”๋ฉด์—์„œ ์˜๋„ํ•œ **๋ฐฐ๊ฒฝ ๊ทธ๋ผ๋””์–ธํŠธ**์™€ **๋กœ๋ (Lottie) ์• ๋‹ˆ๋ฉ”์ด์…˜ ๊ฐ•์กฐ ๊ทธ๋ผ๋””์–ธํŠธ**๊ฐ€ ์ •์ƒ์ ์œผ๋กœ ํ‘œ์‹œ๋˜์ง€ ์•Š๋Š” ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ–ˆ๋‹ค. +- ๊ธฐ์กด์—๋Š” ํ•ด๋‹น ๊ทธ๋ผ๋””์–ธํŠธ๊ฐ€ ์ •์ƒ์ ์œผ๋กœ ๋ Œ๋”๋ง๋˜๊ณ  ์žˆ์—ˆ์œผ๋‚˜, **API ์—ฐ๋™ ์ž‘์—…**๊ณผ **๋ฆฌ๋ฒ ์ด์Šค ๊ณผ์ •**, ๊ทธ๋ฆฌ๊ณ  **์ „์ฒด ๋ ˆ์ด์•„์›ƒ ๊ตฌ์กฐ ์ˆ˜์ •**์„ ๋ฐ˜๋ณตํ•˜๋ฉด์„œ ์˜ˆ์ƒ์น˜ ๋ชปํ•˜๊ฒŒ ๋ ˆ์ด์•„์›ƒ์ด ๊นจ์ง€๊ณ , ๊ทธ๋ผ๋””์–ธํŠธ๊ฐ€ ์ „ํ˜€ ๋ณด์ด์ง€ ์•Š๋Š” ์ƒํ™ฉ์ด ๋ฐœ์ƒํ–ˆ๋‹ค. +- ์ดˆ๊ธฐ ์„ค๊ณ„ ๋‹จ๊ณ„์—์„œ **`position: fixed`๋ฅผ ๊ฐ€๊ธ‰์  ์‚ฌ์šฉํ•˜์ง€ ์•Š์œผ๋ ค๊ณ  ํ–ˆ๋˜ ์„ ํƒ**์ด ์ด๋ฒˆ ๋ฌธ์ œ์— ์˜ํ–ฅ์„ ์ค€ ๊ฒƒ์œผ๋กœ ๋ณด์ธ๋‹ค. ๊ทธ๋ผ๋””์–ธํŠธ๋ฅผ fixed๋กœ ์ฒ˜๋ฆฌํ•˜์ง€ ์•Š๊ณ  ์ƒ๋Œ€์ ์ธ ๋ ˆ์ด์•„์›ƒ์—์„œ ๊ตฌํ˜„ํ•˜๋ ค๋‹ค ๋ณด๋‹ˆ, **์ƒ์œ„ ์ปจํ…Œ์ด๋„ˆ์˜ overflow, z-index, transform ์†์„ฑ** ๋“ฑ์˜ ์˜ํ–ฅ์„ ๋ฐ›์œผ๋ฉด์„œ ์˜๋„์น˜ ์•Š๊ฒŒ ๊ฐ€๋ ค์ง€๋Š” ํ˜„์ƒ์ด ๋ฐœ์ƒํ–ˆ์„ ๊ฐ€๋Šฅ์„ฑ์ด ๋†’์•˜๋‹ค. +- ํŠนํžˆ **๋ฆฌ๋ฒ ์ด์Šค ํ›„ ์ฝ”๋“œ ์ถฉ๋Œ์„ ํ•ด๊ฒฐํ•˜๋ฉด์„œ ์ผ๋ถ€ ์Šคํƒ€์ผ ๋กœ์ง์ด ๋ˆ„๋ฝ๋˜๊ฑฐ๋‚˜ ๋ฎ์–ด์”Œ์›Œ์กŒ์„ ๊ฐ€๋Šฅ์„ฑ**๋„ ์กด์žฌํ–ˆ๋‹ค. ๊ธฐ์กด์— ์ž˜ ๋ณด์ด๋˜ ๊ทธ๋ผ๋””์–ธํŠธ๊ฐ€ ์‚ฌ๋ผ์ง„ ์‹œ์ ์ด ๋ช…ํ™•ํ•˜์ง€ ์•Š์•„ ์›์ธ์„ ์ถ”์ ํ•˜๋Š” ๋ฐ ์‹œ๊ฐ„์ด ์†Œ์š”๋˜์—ˆ๋‹ค. +- QA ๊ณผ์ •์—์„œ Lottie ์• ๋‹ˆ๋ฉ”์ด์…˜์˜ ๊ฐ•์กฐ ์˜์—ญ์ด ์ •์ƒ์ ์œผ๋กœ ํ‘œํ˜„๋˜์ง€ ์•Š์•„, ํ™”๋ฉด์˜ **๊ฐ•์กฐ ํฌ์ธํŠธ๊ฐ€ ์‚ฌ๋ผ์ง€๊ณ  ์‹œ๊ฐ์  ์™„์„ฑ๋„๊ฐ€ ๋–จ์–ด์ง€๋Š” ๋ฌธ์ œ**๊ฐ€ ๋“œ๋Ÿฌ๋‚˜๋ฉด์„œ ํ•ด๋‹น ์ด์Šˆ๊ฐ€ ์ค‘์š”ํ•˜๊ฒŒ ๋ถ€๊ฐ๋˜์—ˆ๋‹ค. + +### โœ” ์›์ธ ๋ถ„์„ + +- ๊ธฐ์กด ๊ตฌ์กฐ์—์„œ๋Š” ๋ฐฐ๊ฒฝ ๊ทธ๋ผ๋””์–ธํŠธ์™€ ๋กœ๋  ๊ฐ•์กฐ ๊ทธ๋ผ๋””์–ธํŠธ๋ฅผ**absolute**๋กœ ํฌ์ง€์…”๋‹ํ•˜์—ฌ,`.matching-success-background`, `.matching-lottie-gradient` ํด๋ž˜์Šค๋ฅผ ํ†ตํ•ด ๋ฐฐ์น˜ํ–ˆ๋‹ค. +- ํ•˜์ง€๋งŒ,**Header**๊ฐ€ ์ƒ์œ„ Layout ์ปดํฌ๋„ŒํŠธ์—์„œ ๋จผ์ € ๋ Œ๋”๋ง๋˜๊ณ , ๋ฐฐ๊ฒฝ ๊ทธ๋ผ๋””์–ธํŠธ๊ฐ€ ํฌํ•จ๋œ MatchingSuccessView๋Š” ๊ทธ ์•„๋ž˜ DOM ๊ณ„์ธต์— ์œ„์น˜ํ•ด ์žˆ์—ˆ๋‹ค. +- ์ด๋•Œ, ์•„๋ฌด๋ฆฌ z-index๋ฅผ ๋†’๊ฒŒ ์ฃผ์–ด๋„ **๋ถ€๋ชจ stacking context**์˜ ์˜ํ–ฅ์œผ๋กœ Header๋ณด๋‹ค ์œ„๋กœ ์˜ฌ๋ผ์˜ค์ง€ ์•Š์•˜๋‹ค. +- **z-index์™€ position ์†์„ฑ์€ DOM ๊ณ„์ธต ๊ตฌ์กฐ์˜ ๋งฅ๋ฝ(=stacking context) ์•ˆ์—์„œ๋งŒ ๋™์ž‘ํ•œ๋‹ค.** +- ๋ถ€๋ชจ ์š”์†Œ๊ฐ€ ๋‚ฎ์€ z-index๋ฅผ ๊ฐ€์ง€๊ฑฐ๋‚˜ stacking context๋ฅผ ์ƒˆ๋กœ ๋งŒ๋“ค๋ฉด, ์ž์‹์ด ์•„๋ฌด๋ฆฌ z-index๋ฅผ ๋†’์—ฌ๋„**๋ถ€๋ชจ์˜ stacking context๋ฅผ ๋ฒ—์–ด๋‚˜์ง€ ๋ชปํ•˜์˜€๋‹ค.** +- ํŠนํžˆ, Header๊ฐ€ ์ƒ์œ„์— ์žˆ๊ณ , ๋ฐฐ๊ฒฝ ๊ทธ๋ผ๋””์–ธํŠธ๊ฐ€ ์ƒ๋Œ€์ ์œผ๋กœ ํ•˜์œ„ DOM์— ์žˆ์œผ๋ฉด z-index๋งŒ ๋†’์—ฌ์„œ๋Š” ์ ˆ๋Œ€ ์œ„๋กœ ์˜ฌ๋ผ์˜ค์ง€ ์•Š๋Š”๋‹ค. + +### โœ” ํ•ด๊ฒฐ ๋ฐฉ๋ฒ• + +### **absolute โ†’ fixed** + +- **absolute** ๋Œ€์‹  **fixed** ํฌ์ง€์…”๋‹์„ ์‚ฌ์šฉํ•˜์—ฌ ํ•ด๊ฒฐํ–ˆ๋‹ค. +- `position: fixed`๋Š” DOM ๊ณ„์ธต๊ณผ ๋ฌด๊ด€ํ•˜๊ฒŒ**๋ทฐํฌํŠธ ๊ธฐ์ค€**์œผ๋กœ ๋ฐฐ์น˜๋˜๋ฏ€๋กœ, stacking context์˜ ์˜ํ–ฅ์„ ๋ฐ›์ง€ ์•Š์•˜๋‹ค. +- ๋ฐฐ๊ฒฝ ๊ทธ๋ผ๋””์–ธํŠธ์™€ ๋กœ๋  ๊ฐ•์กฐ ๊ทธ๋ผ๋””์–ธํŠธ๋ฅผ fixed๋กœ ์„ ์–ธํ•˜์—ฌ,**Header๋ณด๋‹ค ์•„๋ž˜, ์ฃผ์š” ์ฝ˜ํ…์ธ ๋ณด๋‹ค ๋’ค**์— ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ๊น”๋ฆฌ๋„๋ก ์„ค๊ณ„ํ•˜์˜€๋‹ค. + +### **Foreground์™€ Background์˜ ๋ช…ํ™•ํ•œ ๋ถ„๋ฆฌ** + +- **ํ…์ŠคํŠธ, Lottie ์• ๋‹ˆ๋ฉ”์ด์…˜ ๋“ฑ ์ฃผ์š” ์ฝ˜ํ…์ธ **๋Š” +z-10 ์ด์ƒ์œผ๋กœ ๋‘์–ด foreground ๊ณ„์ธต์—์„œ ๋ช…ํ™•ํ•˜๊ฒŒ ํ‘œํ˜„ํ•˜์˜€๋‹ค. +- **๋ฐฐ๊ฒฝ ๊ทธ๋ผ๋””์–ธํŠธ**๋Š” z-0 ์ดํ•˜๋กœ ๋‘์–ด +background ๊ณ„์ธต์—์„œ ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ๊น”๋ฆฌ๋„๋ก ์กฐ์ •ํ•˜์˜€๋‹ค. + +### **Layout ๋ฐ Route ๊ตฌ์กฐ๋Š” ๊ทธ๋Œ€๋กœ** + +- ์ „์ฒด Layout ๋ฐ Route ๊ตฌ์กฐ๋Š” ๊ทธ๋Œ€๋กœ ๋‘๊ณ , **MatchingSuccessView ๋‚ด๋ถ€์—์„œ๋งŒ ํฌ์ง€์…”๋‹์„ ์ˆ˜์ •**ํ•˜์—ฌ ์˜ํ–ฅ ๋ฒ”์œ„๋ฅผ ์ตœ์†Œํ™”ํ–ˆ๋‹ค. +- ์ด ์ ‘๊ทผ๋ฒ• ๋•๋ถ„์— **๋‹ค๋ฅธ ํŽ˜์ด์ง€๋‚˜ ์ปดํฌ๋„ŒํŠธ์— ๋ฏธ์น˜๋Š” ๋ถ€์ž‘์šฉ ์—†์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐ**ํ•  ์ˆ˜ ์žˆ์—ˆ๋‹ค. + +### ์‹ค์ œ CSS ์˜ˆ์‹œ (custom-utilities.css) + +```css +.matching-success-background { + @apply absolute left-1/2 w-[30rem] h-[30rem] blur-3xl rounded-full z-[var(--z-negative-5)]; + top: calc(50% + 10px); + transform: translate(-50%, -50%); + background: radial-gradient(67.17% 67.17% at 33.26% 84.78%, #9be88a 5%, #bcf3ff 88.05%); +} + +.matching-lottie-gradient { + @apply absolute left-1/2 top-1/2 w-[18rem] h-[18rem] -translate-x-1/2 -translate-y-1/2 rounded-full z-[var(--z-negative-1)]; + background: radial-gradient( + 74.24% 74.24% at 50.22% 50.22%, + rgba(255, 255, 255, 0) 46.82%, + #ffffff 72.4% + ); +} +``` + +### ์‹ค์ œ ์ ์šฉ ์˜ˆ์‹œ (MatchingSuccessView) + +```tsx +
+
+
+
+ +
+
+``` + +- ๊ธฐ์กด absolute โ†’ fixed๋กœ ๋ณ€๊ฒฝ +- z-index๋Š” 0 ์ดํ•˜๋กœ ์„ค์ •ํ•˜์—ฌ Header๋ณด๋‹ค ๋’ค์—, ์ฃผ์š” ์ฝ˜ํ…์ธ ๋ณด๋‹ค ์•„๋ž˜์— ์œ„์น˜ + +### โœ” ํšŒ๊ณ  ๋ฐ ๊ฐœ์„  ๋ฐฉํ–ฅ + +- **z-index ๋ฌธ์ œ๋Š” ๋‹จ์ˆœํžˆ ๊ฐ’์˜ ํฌ๊ธฐ๋กœ ํ•ด๊ฒฐ๋˜์ง€ ์•Š๋Š”๋‹ค.** Stacking context์— ๋Œ€ํ•œ ๋ช…ํ™•ํ•œ ์ดํ•ด๊ฐ€ ์—†์œผ๋ฉด ๋ ˆ์ด์•„์›ƒ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์–ด๋ ต๋‹ค๋Š” ์ ์„ ๋‹ค์‹œ ๊นจ๋‹ฌ์•˜๋‹ค. +- `position: fixed`๋Š” **DOM ๊ตฌ์กฐ์— ๊ตฌ์• ๋ฐ›์ง€ ์•Š๊ณ  ์›ํ•˜๋Š” ๋ ˆ์ด์–ด๋ง์„ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋Š” ๊ฐ•๋ ฅํ•œ ๋„๊ตฌ**์ž„์„ ์ฒด๊ฐํ–ˆ๋‹ค. +- ์ด๋ฒˆ ๊ฒฝํ—˜์œผ๋กœ ์ธํ•ด **๋ ˆ์ด์•„์›ƒ์„ ๊ฑด๋“œ๋ฆฌ์ง€ ์•Š๊ณ , ์ปดํฌ๋„ŒํŠธ ๋‹จ์—์„œ ํฌ์ง€์…”๋‹ ์ „๋žต์„ ์œ ์—ฐํ•˜๊ฒŒ ๋ฐ”๊พธ๋Š” ์ ‘๊ทผ๋ฒ•**์ด ํ›จ์”ฌ ํšจ์œจ์ ์ผ ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์„ ๋ฐฐ์› ๋‹ค. \ No newline at end of file diff --git a/docs/trouble/image-1.png b/docs/trouble/image-1.png new file mode 100644 index 00000000..c5c9f3c2 Binary files /dev/null and b/docs/trouble/image-1.png differ diff --git a/docs/trouble/image.png b/docs/trouble/image.png new file mode 100644 index 00000000..e49c1f54 Binary files /dev/null and b/docs/trouble/image.png differ diff --git a/docs/trouble/index.md b/docs/trouble/index.md new file mode 100644 index 00000000..9aa1813b --- /dev/null +++ b/docs/trouble/index.md @@ -0,0 +1,22 @@ +--- +layout: home + +hero: + name: "ํŠธ๋Ÿฌ๋ธ”์ŠˆํŒ… " + tagline: ๋ฉ”์ž‡๋ณผ ํด๋ผ์ด์–ธํŠธ ํŠธ๋Ÿฌ๋ธ”์ŠˆํŒ… ๋ฌธ์„œ๋ฅผ ๋‹ค๋ฃจ๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. + actions: + - theme: brand + text: protectedRoute ์„ค์ • ๊ด€๋ จ + link: /trouble/protectedRoute + - theme: brand + text: useFunnel ๊ธฐ๋ฐ˜ ์˜จ๋ณด๋”ฉ ๊ตฌ์กฐ ๋ถ„๊ธฐ ๋ฐ ์ƒํƒœ ์œ ์ง€ ์ „๋žต + link: /trouble/useFunnel + - theme: brand + text: React Hooks ๊ทœ์น™, Supense ๊ฐ€์ด๋“œ์— ๋งž๋Š” ๋งค์นญ ์นด๋“œ ๊ตฌ์กฐ ๊ฐœ์„  + link: /trouble/suspense + - theme: brand + text: ์‚ฌ๋ผ์ง„ ๊ทธ๋ผ๋””์–ธํŠธ๋ฅผ ์ฐพ์•„์„œ.. + link: /trouble/gradient + +--- + diff --git a/docs/trouble/protectedRoute.md b/docs/trouble/protectedRoute.md new file mode 100644 index 00000000..01f83a99 --- /dev/null +++ b/docs/trouble/protectedRoute.md @@ -0,0 +1,79 @@ +๋กœ๊ทธ์ธ ํ•˜์ง€ ์•Š์€ ์‚ฌ์šฉ์ž๊ฐ€, ๋กœ๊ทธ์ธ ์ดํ›„ ์ ‘๊ทผ ๊ฐ€๋Šฅํ•œ ๊ฒฝ๋กœ๋กœ ์ ‘์†ํ–ˆ์„๋•Œ๋Š” splash ํ™”๋ฉด์œผ๋กœ ์ด๋™ ํ›„ ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€๋กœ ๊ฐ€๋Š” ํ๋ฆ„ + +### โœ” ๋„์ž…ํ•œ ๊ธฐ์ˆ  + +์ด๋ฒˆ ๋กœ๊ทธ์ธ ํ๋ฆ„ ๊ฐœ์„ ์—์„œ๋Š” React Router ๊ธฐ๋ฐ˜์˜ ๋ผ์šฐํŒ… ์‹œ์Šคํ…œ์„ ๊ตฌ์ถ•ํ•˜๋ฉด์„œ, `protected route`์™€ `public route`๋ฅผ ๋ช…ํ™•ํžˆ ๋ถ„๋ฆฌํ•˜๋Š” ๊ตฌ์กฐ๋ฅผ ๋„์ž…ํ–ˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ๋กœ๊ทธ์ธ ์ƒํƒœ์— ๋”ฐ๋ผ ์ ‘๊ทผ ๊ฐ€๋Šฅํ•œ ๊ฒฝ๋กœ๋ฅผ ์—„๊ฒฉํžˆ ์ œ์–ดํ•˜๊ณ ์ž ํ–ˆ๋‹ค. ์ธ์ฆ ์ƒํƒœ ํ™•์ธ๊ณผ ์‚ฌ์šฉ์ž ์ •๋ณด๋ฅผ ํšจ์œจ์ ์œผ๋กœ ๊ด€๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด `tanstack-query`๋ฅผ ํ™œ์šฉํ•˜์—ฌ ์‚ฌ์šฉ์ž ์ƒํƒœ๋ฅผ ์„œ๋ฒ„์—์„œ ์กฐํšŒํ•˜๋Š” `useAuth` ์ปค์Šคํ…€ ํ›…์„ ๋งŒ๋“ค์—ˆ๊ณ , ์ธ์ฆ ํ๋ฆ„ ์ œ์–ด๋Š” `AuthGuard` ์ปดํฌ๋„ŒํŠธ๋กœ ๊ตฌํ˜„ํ–ˆ๋‹ค. ๋˜ํ•œ, ์นด์นด์˜ค ์†Œ์…œ ๋กœ๊ทธ์ธ ์—ฐ๋™ ์‹œ ๋ฐœ์ƒํ•˜๋Š” ์ธ๊ฐ€ ์ฝ”๋“œ๋ฅผ ๋ฐ›์•„ ์„œ๋ฒ„์— ์ „๋‹ฌํ•ด ๋กœ๊ทธ์ธ ์ฒ˜๋ฆฌ๋ฅผ ํ•˜๋Š” `LoginCallback` ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์žˆ๋‹ค. ๋กœ๊ทธ์ธ ๊ณผ์ • ์ค‘ 401 Unauthorized ์ƒํƒœ๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด ์ธํ„ฐ์…‰ํ„ฐ๋กœ ์ด๋ฅผ ๊ฐ์ง€ํ•ด ์ž๋™์œผ๋กœ ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€๋กœ ๋ฆฌ๋‹ค์ด๋ ‰ํŠธํ•˜๋Š” ๋กœ์ง๋„ ํ•จ๊ป˜ ๊ตฌ์„ฑ๋˜์—ˆ๋‹ค. + +### โœ” ๋ฌธ์ œ ์š”์•ฝ + +์ดˆ๊ธฐ์—๋Š” ๋กœ๊ทธ์ธ ํ•„์š” ํŽ˜์ด์ง€์— ๋กœ๊ทธ์ธํ•˜์ง€ ์•Š์€ ์‚ฌ์šฉ์ž๊ฐ€ ์ ‘๊ทผํ•  ๊ฒฝ์šฐ, ์ ์ ˆํ•œ ๋ณดํ˜ธ ๋ฐ ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ ์ฒ˜๋ฆฌ๊ฐ€ ์ฒด๊ณ„์ ์œผ๋กœ ์ด๋ค„์ง€์ง€ ์•Š์•„ ์‚ฌ์šฉ์ž ๊ฒฝํ—˜์ด ์ผ๊ด€๋˜์ง€ ์•Š์•˜๋‹ค. ํŠนํžˆ, ์นด์นด์˜ค ๋กœ๊ทธ์ธ ๋ฒ„ํŠผ ํด๋ฆญ ํ›„ ์ฝœ๋ฐฑ์—์„œ ํ† ํฐ ๋ฐœ๊ธ‰ ๋ฐ ์‚ฌ์šฉ์ž ์ •๋ณด ์กฐํšŒ ํ›„ ํ™”๋ฉด ์ „ํ™˜๊นŒ์ง€์˜ ํ๋ฆ„์ด ๋ช…ํ™•ํ•˜์ง€ ์•Š์•˜๊ณ , ์ธ์ฆ ์ƒํƒœ๋ฅผ ํŒ๋‹จํ•˜๋Š” `useAuth` ํ›…๊ณผ `AuthGuard`์˜ ์—ญํ•  ๋ถ„๋ฆฌ๊ฐ€ ์• ๋งคํ•ด ๋กœ์ง์ด ๋ณต์žกํ•˜๊ฒŒ ์–ฝํ˜€ ์žˆ์—ˆ๋‹ค. ์ด๋กœ ์ธํ•ด ๋กœ๊ทธ์ธ ์„ฑ๊ณต ์—ฌ๋ถ€์™€ ํšŒ์› ๊ฐ€์ž… ์—ฌ๋ถ€ ํŒ๋‹จ ํ›„ ์˜ฌ๋ฐ”๋ฅธ ํ™”๋ฉด์œผ๋กœ ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ์ด๋™์‹œํ‚ค๋Š” ๋ถ€๋ถ„์—์„œ ์˜ˆ์™ธ ์ƒํ™ฉ์ด ๋ฐœ์ƒํ•˜๊ฑฐ๋‚˜ ๋ถˆํ•„์š”ํ•œ ์žฌ๋ Œ๋”๋ง์ด ๋งŽ์•˜๋‹ค. ๋”๋ถˆ์–ด interceptor์—์„œ ๋ฐœ์ƒํ•˜๋Š” 401 ์—๋Ÿฌ ์ฒ˜๋ฆฌ์™€ ์ธ์ฆ ํ๋ฆ„์ด ๋ช…ํ™•ํžˆ ์—ฐ๊ฒฐ๋˜์ง€ ์•Š์•„ ์ค‘๋ณต๋œ ์ธ์ฆ ๊ฒ€์‚ฌ์™€ ๋น„ํšจ์œจ์ ์ธ ๋„ค๋น„๊ฒŒ์ด์…˜์ด ๋ฐœ์ƒํ–ˆ๋‹ค. + +์ถ”๊ฐ€์ ์œผ๋กœ ์ธ์ฆ๋˜์ง€ ์•Š์€ ์‚ฌ์šฉ์ž๊ฐ€ ํ™ˆ ๊ฐ™์€ ์ธ์ฆ ํ•„์š” ๊ฒฝ๋กœ์— ์ ‘๊ทผํ•  ๊ฒฝ์šฐ, Tanstack Query๋ฅผ ํ†ตํ•œ API ์š”์ฒญ์ด ๋จผ์ € ๋ฐœ์ƒํ•ด ์„œ๋ฒ„๋กœ๋ถ€ํ„ฐ 401 Unauthorized ์—๋Ÿฌ๊ฐ€ ๋ฐ˜ํ™˜๋œ๋‹ค. ์ด๋•Œ ์ธ์ฆ ์ƒํƒœ ํŒ๋‹จ ์ „์— API ์š”์ฒญ์ด ๋จผ์ € ์‹คํ–‰๋˜๊ณ , ์ธ์ฆ ์‹คํŒจ(Hi developersโ€ฆ .. ใ…‹ใ…‹) ํ›„ ์Šคํ”Œ๋ž˜์‹œ ํ™”๋ฉด์œผ๋กœ ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ๋˜๋ฉด์„œ ํ™”๋ฉด ๊นœ๋นก์ž„ ํ˜„์ƒ์ด ๋ฐœ์ƒํ•ด ์‚ฌ์šฉ์ž ๊ฒฝํ—˜์ด ๋–จ์–ด์กŒ๋‹ค. + +### โœ” ์›์ธ ๋ถ„์„ + +๊ฐ€์žฅ ํฐ ์›์ธ์€ ์ธ์ฆ ํ๋ฆ„์˜ ๋‹จ๊ณ„๋ณ„ ์—ญํ• ๊ณผ ๊ฒฝ๊ณ„๊ฐ€ ๋ช…ํ™•ํžˆ ์ •์˜๋˜์–ด ์žˆ์ง€ ์•Š์€ ๋ฐ ์žˆ์—ˆ๋‹ค. ์นด์นด์˜ค ๋กœ๊ทธ์ธ ์ฝœ๋ฐฑ์—์„œ ์ธ๊ฐ€ ์ฝ”๋“œ๋ฅผ ๋ฐ›์•„ ์„œ๋ฒ„์— ์ „๋‹ฌํ•˜๊ณ , ์„œ๋ฒ„๋กœ๋ถ€ํ„ฐ ๋กœ๊ทธ์ธ ์„ฑ๊ณต ์‘๋‹ต์„ ๋ฐ›์€ ํ›„ ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์‚ฌ์šฉ์ž ์ •๋ณด๋ฅผ ์กฐํšŒํ•ด ๋กœ๊ทธ์ธ ์ƒํƒœ๋ฅผ ํŒ๋‹จํ•˜๋Š” ๋ถ€๋ถ„์ด ๋ถ„๋ฆฌ๋˜์–ด ์žˆ์—ˆ๊ณ , ์ด ์‚ฌ์ด์˜ ์ƒํƒœ ๊ด€๋ฆฌ๊ฐ€ ์ผ๊ด€์ ์ด์ง€ ์•Š์•˜๋‹ค. ๋˜ํ•œ, `useAuth` ํ›…์ด ์‚ฌ์šฉ์ž ์ƒํƒœ๋ฅผ ์กฐํšŒํ•˜์ง€๋งŒ ์ด ๊ฒฐ๊ณผ๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ `AuthGuard`๊ฐ€ ๊ฒฝ๋กœ ์ ‘๊ทผ์„ ์ œ์–ดํ•˜๋Š” ์—ญํ• ์ด ๋šœ๋ ทํ•˜๊ฒŒ ๊ตฌ๋ถ„๋˜์ง€ ์•Š์•„ ์ฑ…์ž„์ด ๋ถ„์‚ฐ๋˜์—ˆ๋‹ค. interceptor๋Š” 401 ์ƒํƒœ ๋ฐœ์ƒ ์‹œ ๋กœ๊ทธ์•„์›ƒ ํ˜น์€ ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€ ์ด๋™์„ ์ฒ˜๋ฆฌํ•˜์ง€๋งŒ, ๊ทธ ํ๋ฆ„์ด `useAuth`๋‚˜ ๋ผ์šฐํ„ฐ์™€ ์กฐํ™”๋กญ๊ฒŒ ์—ฐ๊ฒฐ๋˜์ง€ ๋ชปํ•ด ์ค‘๋ณต ๊ฒ€์‚ฌ์™€ ์˜ˆ์™ธ ์ฒ˜๋ฆฌ๊ฐ€ ๋ฐ˜๋ณต๋๋‹ค. ๊ฒฐ๊ณผ์ ์œผ๋กœ ๋กœ๊ทธ์ธ ์ „, ๋กœ๊ทธ์ธ ํ›„ ํ™”๋ฉด ์ „ํ™˜๊ณผ ์ƒํƒœ ๋ฐ˜์˜์ด ๋น„๋™๊ธฐ์ ์œผ๋กœ ๊ผฌ์—ฌ ํ๋ฆ„ ์ œ์–ด๊ฐ€ ์–ด๋ ค์› ๋‹ค.๊นŒ๊นœ + +๊นœ๋นก์ž„ ๊ด€๋ จ ํ˜„์ƒ์€, ๋ผ์šฐํ„ฐ์—์„œ ์ธ์ฆ ๋ณดํ˜ธ ๊ธฐ๋Šฅ(`AuthGuard`)์ด ์ž์‹ ์ปดํฌ๋„ŒํŠธ ๋ Œ๋”๋ง ์ „์— ์„ ํ–‰๋˜์ง€ ์•Š์•„, ์ธ์ฆ ๊ฒ€์ฆ ์ „ API ์š”์ฒญ์ด ๋ฐœ์ƒํ•˜๋Š” ๋ฌธ์ œ๊ฐ€ ์žˆ์—ˆ๋‹ค. ๋˜ํ•œ ๋ผ์šฐํ„ฐ์— ์—๋Ÿฌ ์ฒ˜๋ฆฌ์šฉ `errorElement`๊ฐ€ ์—†์–ด์„œ 401 ์—๋Ÿฌ๋กœ ์ธํ•œ ์˜ˆ์™ธ ์ƒํ™ฉ์ด ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ํ•ธ๋“ค๋ง๋˜์ง€ ์•Š์•˜๋‹ค. ๊ฒฐ๊ณผ์ ์œผ๋กœ ์‚ฌ์šฉ์ž๋Š” ์ธ์ฆ ์ƒํƒœ ํ™•์ธ ์ด์ „์— ๋ถˆํ•„์š”ํ•œ API ํ˜ธ์ถœ๊ณผ ๊นœ๋นก์ž„ ํ˜„์ƒ์„ ๊ฒฝํ—˜ํ–ˆ๋‹ค. + +### โœ” ํ•ด๊ฒฐ ๋ฐฉ๋ฒ• + +- ๋ผ์šฐํ„ฐ ๊ตฌ์กฐ ์žฌ์„ค๊ณ„: React Router์˜ createBrowserRouter๋ฅผ ํ™œ์šฉํ•ด, ๋กœ๊ทธ์ธ ํ•„์š” ๊ฒฝ๋กœ๋ฅผ AuthGuard ์ปดํฌ๋„ŒํŠธ๋กœ ๊ฐ์‹ธ๊ณ , ๋กœ๊ทธ์ธ ์ „์šฉ ๊ฒฝ๋กœ๋Š” publicRoutes๋กœ ๋ถ„๋ฆฌํ•ด ๋‘์—ˆ๋‹ค. ์ด๋กœ์จ ์ธ์ฆ ์—ฌ๋ถ€์— ๋”ฐ๋ผ ์ ‘๊ทผ ๊ฐ€๋Šฅํ•œ ๊ฒฝ๋กœ๊ฐ€ ์—„๊ฒฉํžˆ ๊ตฌ๋ถ„๋˜๋„๋ก ํ–ˆ๋‹ค. +- useAuth ํ›… ๊ฐœ์„ : ์„œ๋ฒ„์—์„œ ์‚ฌ์šฉ์ž ์ƒํƒœ๋ฅผ ์กฐํšŒํ•ด ๋‹‰๋„ค์ž„ ์กด์žฌ ์—ฌ๋ถ€(isAuthenticated)์™€ ๊ฐ€์ž… ์กฐ๊ฑด(isNotMatched) ๋“ฑ์„ ๋ช…ํ™•ํžˆ ๋ฐ˜ํ™˜ํ•˜๋„๋ก ํ•˜์—ฌ, ๋กœ๊ทธ์ธ ์—ฌ๋ถ€ ๋ฐ ์ถ”๊ฐ€ ๋งค์นญ ํ•„์š” ์—ฌ๋ถ€๋ฅผ ํŒ๋ณ„ํ•˜๋Š” ๋กœ์ง์„ ์ผ์›ํ™”ํ–ˆ๋‹ค. ์บ์‹œ ๋ฌดํšจํ™” ๊ธฐ๋Šฅ์„ ํ™œ์šฉํ•ด ์‚ฌ์šฉ์ž ์ƒํƒœ ๊ฐฑ์‹ ๋„ ์‰ฝ๊ฒŒ ํ•  ์ˆ˜ ์žˆ๋„๋ก ์„ค๊ณ„ํ–ˆ๋‹ค. +- AuthGuard ์ปดํฌ๋„ŒํŠธ ์—ญํ•  ๋ช…ํ™•ํ™”: useAuth์—์„œ ๋ฐ˜ํ™˜๋œ ๋กœ๊ทธ์ธ ์ƒํƒœ์™€ ๋กœ๋”ฉ ์ƒํƒœ๋ฅผ ํ† ๋Œ€๋กœ ๋กœ๊ทธ์ธ๋˜์ง€ ์•Š์€ ๊ฒฝ์šฐ Navigate ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ด์šฉํ•ด ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€๋กœ ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ์‹œํ‚ค๊ณ , ์ธ์ฆ ์ค‘์ด๋ฉด ๋กœ๋”ฉ ์ƒํƒœ๋ฅผ ๋ณด์—ฌ์ฃผ๋„๋ก ํ•˜์—ฌ ์ ‘๊ทผ ์ œ์–ด๋ฅผ ์—„๊ฒฉํ•˜๊ฒŒ ๊ตฌํ˜„ํ–ˆ๋‹ค. +- ๊นœ๋นก์ž„ ๊ด€๋ จ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์œผ๋กœ๋Š” , ๋ผ์šฐํ„ฐ์—์„œ `AuthGuard`๋ฅผ ์ตœ์ƒ์œ„ ๋ ˆ๋ฒจ๋กœ ๋ฐฐ์น˜ํ•ด, ์ธ์ฆ ์—ฌ๋ถ€ ํ™•์ธ์ด ๋จผ์ € ์ด๋ฃจ์–ด์ง€๊ณ  ์ž์‹ ๋ผ์šฐํŠธ๋“ค์ด ๋ Œ๋”๋ง ๋˜๋„๋ก ๋ณ€๊ฒฝํ–ˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ์ธ์ฆ์ด ์•ˆ ๋œ ๊ฒฝ์šฐ ์ž์‹ ์ปดํฌ๋„ŒํŠธ๋“ค์˜ API ์š”์ฒญ ์ž์ฒด๋ฅผ ๋ง‰์•˜๋‹ค. ๋˜, ๋ผ์šฐํ„ฐ์— `errorElement`๋ฅผ ๋นˆ ์ปดํฌ๋„ŒํŠธ ๋˜๋Š” ๋ณ„๋„ ์—๋Ÿฌ UI๋กœ ์ถ”๊ฐ€ํ•ด ์˜ˆ์™ธ ์ƒํ™ฉ์„ ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ์ฒ˜๋ฆฌํ•˜๋„๋ก ํ•จ์œผ๋กœ์จ, ์˜ˆ๊ธฐ์น˜ ์•Š์€ ์—๋Ÿฌ ๋ฐœ์ƒ ์‹œ ์‚ฌ์šฉ์ž์—๊ฒŒ ๋ถˆํ•„์š”ํ•œ ๊นœ๋นก์ž„์„ ๋ณด์—ฌ์ฃผ์ง€ ์•Š๋„๋ก ํ–ˆ๋‹ค. `AuthGuard` ์ปดํฌ๋„ŒํŠธ์—์„œ ์ธ์ฆ ์ƒํƒœ ๋กœ๋”ฉ ์ค‘์—” ์Šคํ”Œ๋ž˜์‹œ ํ™”๋ฉด์„ ๋ Œ๋”๋งํ•˜๊ณ , ์ธ์ฆ ์‹คํŒจ ์‹œ ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€๋กœ ์ฆ‰์‹œ ๋ฆฌ๋‹ค์ด๋ ‰ํŠธํ•˜๋„๋ก ๊ฐœ์„ ํ•ด ์‚ฌ์šฉ์ž ๊ฒฝํ—˜์„ ๋ถ€๋“œ๋Ÿฝ๊ฒŒ ๋งŒ๋“ค์—ˆ๋‹ค. + +- ์ฝ”๋“œ ์ผ๋ถ€โ€ฆ + + ```tsx + // router.tsx + import { createBrowserRouter } from 'react-router-dom'; + import AuthGuard from '@routes/auth-guard'; + import Layout from '@routes/layout'; + import Splash from '@pages/login/components/splash'; + import ErrorView from '@pages/error/error-view'; + import { protectedRoutes } from '@routes/protected-routes'; + import { publicRoutes } from '@routes/public-routes'; + import { ROUTES } from '@routes/routes-config'; + + export const router = createBrowserRouter([ + { + path: ROUTES.SPLASH, + element: , + }, + ...publicRoutes, + { + path: '/', + element: , // ์ตœ์ƒ์œ„์— AuthGuard ๋ฐฐ์น˜ + errorElement: <>, // ๋นˆ ์ปดํฌ๋„ŒํŠธ๋‚˜ ๋ณ„๋„์˜ ์—๋Ÿฌ UI๋กœ ๊นœ๋นก์ž„ ๋ฐฉ์ง€ + children: [ + { + element: , + children: [ + ...protectedRoutes, + { + path: '/error', + element: , + }, + { + path: '*', + element: ( + + ), + }, + ], + }, + ], + }, + ]); + + ``` + + +### โœ” ํšŒ๊ณ  ๋ฐ ๊ฐœ์„  ๋ฐฉํ–ฅ + +์ด๋ฒˆ ๋กœ๊ทธ์ธ ํ๋ฆ„ ์„ค๊ณ„ ๋„์ „์€ protected route์™€ public route๋ฅผ ๋ช…ํ™•ํžˆ ๋ถ„๋ฆฌํ•˜์—ฌ, ์ธ์ฆ ์ƒํƒœ์— ๋”ฐ๋ฅธ ์‚ฌ์šฉ์ž ๊ฒฝํ—˜์„ ์ฒด๊ณ„์ ์œผ๋กœ ๊ด€๋ฆฌํ•˜๋Š” ๋ฐ ํฐ ๋„์›€์ด ๋˜์—ˆ๋‹ค. ํ•˜์ง€๋งŒ ์นด์นด์˜ค ๋กœ๊ทธ์ธ ์ฝœ๋ฐฑ ์ดํ›„ ์ธ๊ฐ€ ์ฝ”๋“œ ์ฒ˜๋ฆฌ๋ถ€ํ„ฐ ์‚ฌ์šฉ์ž ์ƒํƒœ ์กฐํšŒ ๋ฐ ํ™”๋ฉด ์ „ํ™˜๊นŒ์ง€ ์ด์–ด์ง€๋Š” ๋น„๋™๊ธฐ ํ๋ฆ„์ด ๋ณต์žกํ•˜์—ฌ, interceptor, useAuth, AuthGuard ๋“ฑ ์—ฌ๋Ÿฌ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์ธ์ฆ ํ๋ฆ„์˜ ์ผ๋ถ€๋ฅผ ๋ถ„๋‹ดํ•˜๋Š” ๊ณผ์ •์—์„œ ์ƒํƒœ ๋ณ€ํ™”๊ฐ€ ์ฆ‰์‹œ ๋ฐ˜์˜๋˜์ง€ ์•Š์•„ ๋กœ์ง ๊ผฌ์ž„๊ณผ ๋””๋ฒ„๊น… ์–ด๋ ค์›€์ด ์žˆ์—ˆ๋‹ค. + +์•ž์œผ๋กœ๋Š” ์ธ์ฆ ํ๋ฆ„ ๋‚ด ๊ฐ ์—ญํ• ๋ณ„ ์ฑ…์ž„๊ณผ ์ƒํƒœ ๋ณ€ํ™”๋ฅผ ๋”์šฑ ๋ช…ํ™•ํžˆ ๊ตฌ๋ถ„ํ•˜๋Š” ๋™์‹œ์—, ์ „์—ญ ์ƒํƒœ ๊ด€๋ฆฌ ์†”๋ฃจ์…˜(Recoil, Zustand ๋“ฑ)์„ ๋„์ž…ํ•ด ์ธ์ฆ ์ƒํƒœ ๋ณ€ํ™”๋ฅผ ์ผ๊ด€์„ฑ ์žˆ๊ฒŒ ์ฒ˜๋ฆฌํ•˜๋Š” ๋ฐฉ์•ˆ์„ ๊ณ ๋ฏผํ•  ์˜ˆ์ •์ด๋‹ค. ๋˜ํ•œ ๋„คํŠธ์›Œํฌ ์˜ค๋ฅ˜, ํ† ํฐ ๋งŒ๋ฃŒ ๋“ฑ ๋‹ค์–‘ํ•œ ์˜ˆ์™ธ ์ฒ˜๋ฆฌ ์ผ€์ด์Šค๋ฅผ ์„ธ๋ฐ€ํ•˜๊ฒŒ ํ…Œ์ŠคํŠธํ•˜์—ฌ ์‚ฌ์šฉ์ž ์ดํƒˆ์„ ๋ฐฉ์ง€ํ•˜๋Š” UX ๊ฐœ์„ ์—๋„ ์ฃผ๋ ฅํ•  ๊ณ„ํš์ด๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ๋กœ๊ทธ์ธ๊ณผ ์ธ์ฆ ๋กœ์ง์„ ๋”์šฑ ๊ฒฌ๊ณ ํ•˜๊ณ  ํ™•์žฅ์„ฑ ์žˆ๊ฒŒ ๋‹ค๋“ฌ๋Š” ๊ฒƒ์ด ๋ชฉํ‘œ๋‹ค. + +์ด๋ฒˆ ๊ฐœ์„  ์ž‘์—…์„ ํ†ตํ•ด ์ธ์ฆ ์ƒํƒœ๊ฐ€ ์™„์ „ํžˆ ํ™•์ธ๋œ ํ›„์—๋งŒ protected route ๋‚ด๋ถ€ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋ Œ๋”๋ง๋˜๋„๋ก ํ•˜์—ฌ, ๋ถˆํ•„์š”ํ•œ API ํ˜ธ์ถœ๊ณผ 401 ์—๋Ÿฌ๋กœ ์ธํ•œ ํ™”๋ฉด ๊นœ๋นก์ž„ ํ˜„์ƒ์„ ์›์ฒœ ์ฐจ๋‹จํ•  ์ˆ˜ ์žˆ์—ˆ๋‹ค. ๋•๋ถ„์— ์Šคํ”Œ๋ž˜์‹œ ํ™”๋ฉด์ด ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ๋…ธ์ถœ๋˜์–ด ์‚ฌ์šฉ์ž ๊ฒฝํ—˜์ด ํฌ๊ฒŒ ํ–ฅ์ƒ๋˜์—ˆ๋‹ค. ์•ž์œผ๋กœ๋„ ์ธ์ฆ๊ณผ ๊ด€๋ จ๋œ ๋น„๋™๊ธฐ ์ƒํƒœ ๊ด€๋ฆฌ๋Š” ๋ผ์šฐํ„ฐ ์ˆ˜์ค€์—์„œ ๊ด€๋ฆฌํ•˜์—ฌ ํŽ˜์ด์ง€ ๋ Œ๋”๋ง ํƒ€์ด๋ฐ๊ณผ API ํ˜ธ์ถœ ํ๋ฆ„์„ ์ตœ๋Œ€ํ•œ ์ผ์น˜์‹œํ‚ค๋Š” ๋ฐฉํ–ฅ์œผ๋กœ ์„ค๊ณ„ํ•  ๊ณ„ํš์ด๋‹ค. ๋˜ํ•œ, ์—๋Ÿฌ ํ•ธ๋“ค๋ง UI๋„ ์ผ๊ด€์„ฑ ์žˆ๊ฒŒ ๊ตฌ์„ฑํ•ด ์‚ฌ์šฉ์ž ์ดํƒˆ์„ ์ตœ์†Œํ™”ํ•˜๋Š” ๋ฐ ์ง‘์ค‘ํ•  ์˜ˆ์ •์ด๋‹ค. \ No newline at end of file diff --git a/docs/trouble/suspense.md b/docs/trouble/suspense.md new file mode 100644 index 00000000..7c34dfc9 --- /dev/null +++ b/docs/trouble/suspense.md @@ -0,0 +1,115 @@ +### โœ” ๋ฌธ์ œ ์š”์•ฝ + +**๊ธฐ์กด useMatchCreate**ย ํ›…์€ ๋‘ API(**`SINGLE_MATCH_RESULT`**,ย **`GROUP_MATCH_RESULT`**)์™€ Mock ๋ฐ์ดํ„ฐ(**`mockMateSingle`**)๋ฅผ ๋ชจ๋‘ ํ•œ ๊ณณ์—์„œ ๋‹ค๋ฃจ๋ฉด์„œ,ย **`type`**์ด๋ผ๋Š” Prop์— ๋”ฐ๋ผ ๋ถ„๊ธฐ ์ฒ˜๋ฆฌํ•˜๋„๋ก ์„ค๊ณ„๋˜์–ด ์žˆ์—ˆ๋‹ค. + +```tsx +const useMatchCreate = (matchId: number, type: 'single' | 'group' | null | undefined) => { + // ๊ทธ๋ฃน ๊ฒฐ๊ณผ ์กฐํšŒ ์š”์ฒญ + const { data: mateGroup } = useSuspenseQuery( + matchQueries.GROUP_MATCH_RESULT(matchId, type === 'group') + ); + + const getMatchData = (): MatchCardData | null => { + if (type === 'single') { ... } // mock ๋ฐ์ดํ„ฐ ๋ฐ˜ํ™˜ + if (!mateGroup) return null; + return { ...mateGroup, type: 'group' }; // ๊ทธ๋ฃน API ์‘๋‹ต ๋ฐ˜ํ™˜ + }; + + return { matchData: getMatchData() }; +}; + +``` + +- **๋ฌธ์ œ 1: ํƒ€์ž…์— ๋”ฐ๋ผ ์ฟผ๋ฆฌ/๋ฐ์ดํ„ฐ ๋ถ„๊ธฐ๊ฐ€ ๋™์ ์œผ๋กœ ์ผ์–ด๋‚จ.** + + **`type`**์ดย **`group`**์ผ ๋•Œ๋Š”ย **`useSuspenseQuery`**๋กœ ๊ทธ๋ฃน ๋งค์น˜ ๊ฒฐ๊ณผ๋ฅผ ๋ถˆ๋Ÿฌ์˜ค๊ณ , + + **`type`**์ดย **`single`**์ผ ๋•Œ๋Š” mock ๋ฐ์ดํ„ฐ๋ฅผ ์‚ฌ์šฉํ•˜๋„๋ก ๋ถ„๊ธฐ ์ฒ˜๋ฆฌ๋จ. + +- **๋ฌธ์ œ 2: ๋‘ ์ฟผ๋ฆฌ ํ›…์„ ๋™์‹œ์— ์„ ์–ธํ•˜๊ณ , ์กฐ๊ฑด๋ถ€๋กœ ๋ฐ˜ํ™˜.** + + ํ›… ๋‚ด๋ถ€์—ย **`useSuspenseQuery`**๊ฐ€ ํ•œ ๋ฒˆ๋งŒ ์žˆ์„ ๊ฒƒ ๊ฐ™์ง€๋งŒ,ย **`type`**์ดย **`group`**์ด๋ฉด ํ•ญ์ƒย **`useSuspenseQuery`**๊ฐ€ ์‹คํ–‰๋จ. + + **`type`**์ดย **`single`**์ด๋ฉด ์ด ํ›…์€ ์‹คํ–‰๋˜์ง€ ์•Š์ง€๋งŒ, ๋‹ค๋ฅธ ์ปดํฌ๋„ŒํŠธ์—์„œ์˜ ์‚ฌ์šฉ์ด ๋ช…ํ™•ํ•˜์ง€ ์•Š์Œ. + +- **๋ฌธ์ œ 3: mock ๋ฐ์ดํ„ฐ์™€ API ๋ฐ์ดํ„ฐ๋ฅผ ์„ž์–ด ์“ฐ๊ณ  ์žˆ์Œ.** + + **`single`**ย ํƒ€์ž… ๊ฒฐ๊ณผ๋Š” mock์ด๊ณ ,ย **`group`**ย ํƒ€์ž… ๊ฒฐ๊ณผ๋Š” API ๋ฐ์ดํ„ฐ์—์„œ ๊ฐ€์ ธ์˜ด. ์ด๋Š” ๋ฏธ๋ž˜์— API ์ „ํ™˜ ์‹œ ์œ ์ง€๋ณด์ˆ˜๋ฅผ ํž˜๋“ค๊ฒŒ ํ•จ. + +- **๋ฌธ์ œ 4: ์กฐ๊ฑด๋ถ€ ๋ Œ๋”๋ง์ด ํ›… ๋‚ด๋ถ€์—์„œ ์ผ์–ด๋‚จ.** + + ์ด ๊ตฌ์กฐ๋Š” React Hook ๊ทœ์น™์ƒ ๋ฌด์กฐ๊ฑด ํ›…์€ย **ํ•ญ์ƒ ๊ฐ™์€ ์œ„์น˜์—์„œ ํ˜ธ์ถœ๋˜์–ด์•ผ**ย ํ•œ๋‹ค๋Š” ์›์น™์„ ์–ด๊ธฐ๊ฒŒ ๋จ. + + +### โœ” ์›์ธ ๋ถ„์„ + +- **2-1. useSuspenseQuery๋Š” ์กฐ๊ฑด๋ถ€๋กœ ํ˜ธ์ถœํ•  ์ˆ˜ ์—†์Œ** + + **`type`**์— ๋”ฐ๋ผย **`useSuspenseQuery`**๋ฅผ ๋ฐ”๋กœ๋ฐ”๋กœ ๋ฐ”๊ฟ”์„œ ์“ฐ๋ฉด, ๋ฆฌ์•กํŠธ๋Š” ํ›… ํ˜ธ์ถœ ์ˆœ์„œ๋ฅผ ๊ธฐ์ค€์œผ๋กœ ๋‚ด๋ถ€ ์ƒํƒœ๋ฅผ ๊ด€๋ฆฌํ•˜๋ฏ€๋กœ **`type`**์ด ๋ฐ”๋€Œ๋ฉด ํ˜ธ์ถœ ์ˆœ์„œ๊ฐ€ ๊ผฌ์—ฌ ์—๋Ÿฌ ๋ฐœ์ƒ! + +- **2-2. enabled๋กœ ์กฐ๊ฑด๋ถ€ ์‹คํ–‰์„ ์‹œ๋„** + + **`useSuspenseQuery`**์—์„œย **`enabled`**ย ์˜ต์…˜(**`GROUP_MATCH_RESULT(matchId, type === 'group')`**)์„ ์ค˜๋„ + + ์ด๋Š” ๋‹จ์ˆœํžˆ ์ฟผ๋ฆฌ ๊ฒฐ๊ณผ์˜ย **`data`**์™€ย **`isFetching`**ย ๋“ฑ์„ ์ œ์–ดํ•  ๋ฟ, ํ›… ์ž์ฒด๊ฐ€ย **์‹คํ–‰ ์ž์ฒด๋ฅผ ์–ต์ œํ•˜๋Š” ๊ฒƒ์€ ์•„๋‹˜**. ์ฆ‰,ย **`type`**์ดย **`group`**์ด๋“ ย **`single`**์ด๋“ ย **ํ›…์€ ํ•ญ์ƒ ์‹คํ–‰**๋จ. + +- **2-3. API ํ˜ธ์ถœ์ด ๋ถˆํ•„์š”ํ•˜๊ฒŒ ๋ฐœ์ƒ** + + **`type`**์ดย **`single`**์ด๋”๋ผ๋„ ๊ทธ๋ฃน ๋งค์นญ ๊ฒฐ๊ณผ ์กฐํšŒ API๊ฐ€ ์‹คํ–‰๋จ. ๋ฐ˜๋Œ€๋กœ,ย **`group`**์ธ๋ฐ๋„ย **`single`**(mock) ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ ๋กœ์ง์ด ์ƒ๊ด€์—†์ด ์žˆ๋‹ค๋Š” ๊ตฌ์กฐ์  ํ˜ผ๋™์ด ์กด์žฌํ•จ. + +- **2-4. ํ›…๊ณผ ์ปดํฌ๋„ŒํŠธ์˜ ์ฑ…์ž„ ๋ถ„๋ฆฌ ํ•„์š”** + + **`useMatchCreate`**๊ฐ€ย **API ํ˜ธ์ถœ**,ย **mock ๋ฐ์ดํ„ฐ ๋ฐ˜ํ™˜**,ย **ํƒ€์ž… ํŒ๋‹จ**,ย **์นด๋“œ ๋ฐ์ดํ„ฐ ๋ณ€ํ™˜**๊นŒ์ง€ ํ•œ ๋ฒˆ์— ๋ชจ๋‘ ๋‹ด๋‹นํ•˜๋ฉด, ์œ ์ง€ ๋ณด์ˆ˜์™€ ํ™•์žฅ์ด ์–ด๋ ต๊ณ , ์‹ค์ œ๋กœย **ํ›… ๊ทœ์น™ ์œ„๋ฐ˜**์œผ๋กœ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•จ. + + +### โœ” ํ•ด๊ฒฐ ๋ฐฉ๋ฒ• + +**2-1. ํ›…๊ณผ ์ปดํฌ๋„ŒํŠธ ๊ตฌ์กฐ ๋ถ„๋ฆฌ** + +- **SingleMatchCard**: ์‹ฑ๊ธ€ ๋งค์นญ ๋ฐ์ดํ„ฐ๋งŒ์„ ๋ฐ›์•„ ํ‘œ์‹œํ•˜๋Š” ์ปดํฌ๋„ŒํŠธ +- **GroupMatchCard**: ๊ทธ๋ฃน ๋งค์นญ ๋ฐ์ดํ„ฐ๋งŒ์„ ๋ฐ›์•„ ํ‘œ์‹œํ•˜๋Š” ์ปดํฌ๋„ŒํŠธ +- **MatchCardSection**: ํƒ€์ž…(**`type`**)์— ๋”ฐ๋ผ Single/Group ์ปดํฌ๋„ŒํŠธ๋ฅผ ์กฐ๊ฑด๋ถ€ ๋ Œ๋”๋ง + +```tsx +// MatchCardSection.tsx +const MatchCardSection = ({ matchId, type }: MatchCardSectionProps) => { + if (type === 'single') return ; + if (type === 'group') return ; + return null; +}; +``` + +์žฅ์ : ํƒ€์ž…๋ณ„๋กœ ํ›…(์ฟผ๋ฆฌ) ํ˜ธ์ถœ๊ณผ ๋ฐ์ดํ„ฐ ๋ณ€ํ™˜ ๋กœ์ง์ด ๋ช…ํ™•ํžˆ ๋ถ„๋ฆฌ๋˜์–ดย ํ›… ๊ทœ์น™์„ ์ฒ ์ €ํžˆ ์ง€ํ‚ฌ ์ˆ˜ ์žˆ์Œ + +**2-2. Mock -> API ์ „ํ™˜์ด ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ์—ฐ๊ฒฐ** + +๊ธฐ์กด์—๋Š”ย **`single`**์ด๋ฉด ๋ฌด์กฐ๊ฑด mock์„ ์“ฐ๋‹ค๊ฐ€, ์ด์ œ๋Š”ย **SingleMatchCard ์ปดํฌ๋„ŒํŠธ ๋‹จ์—์„œ๋„ ์‹ค์ œ API๋ฅผ ์‚ฌ์šฉํ•˜๋„๋ก**ย ์„ค๊ณ„๋งŒ ์กฐ๊ธˆ๋งŒ ๋ฐ”๊พธ๋ฉด ์‰ฝ๊ฒŒ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ํ•  ์ˆ˜ ์žˆ์Œ. + +**2-3. ๋ฐ์ดํ„ฐ ํ๋ฆ„์˜ ์ผ๊ด€์„ฑ ํ™•๋ณด** + +- **SingleMatchCard**:ย **`useSuspenseQuery(matchQueries.SINGLE_MATCH_RESULT(matchId))`** +- **GroupMatchCard**:ย **`useSuspenseQuery(matchQueries.GROUP_MATCH_RESULT(matchId))`** + +๊ฐ ์ปดํฌ๋„ŒํŠธ๋Š”ย **์ž์‹ ์˜ ํƒ€์ž…์— ๋งž๋Š”**ย ์ฟผ๋ฆฌ๋งŒ ํ›…์œผ๋กœ ํ˜ธ์ถœํ•จ. ๋ถˆํ•„์š”ํ•œ API ํ˜ธ์ถœ, mock ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ ๋“ฑ์„ ๊ฑฑ์ •ํ•  ํ•„์š”๊ฐ€ ์—†์Œ. + +**2-4. React Hook ๊ทœ์น™ ์—„์ˆ˜** + +ํ›… ํ˜ธ์ถœ์€ย **์ปดํฌ๋„ŒํŠธ ์ƒ๋‹จ์—์„œ ๋ฌด์กฐ๊ฑด ๋™์ผํ•œ ์ˆœ์„œ๋กœ**. ์กฐ๊ฑด๋ถ€ ๋ Œ๋”๋ง์€ ์ปดํฌ๋„ŒํŠธ ํŠธ๋ฆฌ์—์„œ JSX ๋ ˆ๋ฒจ์—์„œ ์ฒ˜๋ฆฌ. + +โ†’ย **ํ›… ๋‚ด๋ถ€์—์„œ ์กฐ๊ฑด๋ถ€ ์ฒ˜๋ฆฌ๊ฐ€ ์•„๋‹ˆ๋ผ, ํŠธ๋ฆฌ(์ปดํฌ๋„ŒํŠธ ๋ ˆ๋ฒจ)์—์„œ ์กฐ๊ฑด๋ถ€๋กœ ๋ Œ๋”๋ง**์„ ํ•˜๊ฒŒ ๋˜๋ฏ€๋กœ, ํ›… ๊ทœ์น™์„ ์ ˆ๋Œ€๋กœ ์–ด๊ธฐ์ง€ ์•Š์Œ. + +**2-5. Suspense๋กœ ๋ฐ์ดํ„ฐ ๋กœ๋“œ ๋ฐ ์—๋Ÿฌ ์ฒ˜๋ฆฌ ์šฉ์ด** + +Suspense๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ,ย **๋ฐ์ดํ„ฐ๊ฐ€ ์ค€๋น„๋œ ํ›„ ๋ Œ๋”๋ง**๋˜๋ฏ€๋กœ **`undefined`**๋กœ ์ธํ•œ ๊นœ๋นก์ž„, ์Šคํƒ€์ผ ์ด์Šˆ ๋“ฑ์„ ์™„์ „ํžˆ ๋ฐฉ์ง€. + +### โœ” ํšŒ๊ณ  ๋ฐ ๊ฐœ์„  ๋ฐฉํ–ฅ + +์ปดํฌ๋„ŒํŠธ ๊ตฌ์กฐ ๊ฐœ์„ ์„ ํ†ตํ•ด ๋งค์นญ ํƒ€์ž…(์‹ฑ๊ธ€/๊ทธ๋ฃน)๋ณ„๋กœ ๊ธฐ์กด์— ํ•œ๊ณณ์—์„œ ๋‹ด๋‹นํ•˜๋˜ ๋ณต์žกํ•œ ๋กœ์ง์„,ย **๊ฐ์ž์˜ ์—ญํ• ์— ๋งž๊ฒŒ ๋ถ„๋ฆฌ**ํ•จ์œผ๋กœ์จ ์—ฌ๋Ÿฌ ๋ฌธ์ œ๋ฅผ ๋ช…ํ™•ํ•˜๊ฒŒ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ์—ˆ๋‹ค. ๊ธฐ์กด์—๋Š” ํƒ€์ž… ๊ตฌ๋ถ„์ด ํ›… ๋‚ด๋ถ€์—์„œ ์กฐ๊ฑด๋ถ€๋กœ ์ฒ˜๋ฆฌ๋˜๋‹ค ๋ณด๋‹ˆ, ํ›…์ด ํ•ญ์ƒ ๊ฐ™์€ ์ˆœ์„œ๋กœ ํ˜ธ์ถœ๋˜์–ด์•ผ ํ•œ๋‹ค๋Š”ย **React Hooks ๊ทœ์น™**์„ ์–ด๊ธธ ์ˆ˜๋ฐ–์— ์—†์—ˆ๊ณ , ์ด๋กœ ์ธํ•ด ์˜ˆ๊ธฐ์น˜ ์•Š์€ ๋ฒ„๊ทธ์™€ ๋””๋ฒ„๊น…์˜ ์–ด๋ ค์›€์ด ๋ฐœ์ƒํ–ˆ๋‹ค. ๋˜ํ•œ, API์™€ mock ๋ฐ์ดํ„ฐ๊ฐ€ ํ˜ผ์žฌ๋˜์–ด ์žˆ์–ด, ์‹ค์ œ ์„œ๋น„์Šค ์—ฐ๋™ ์‹œย **๋ถˆํ•„์š”ํ•œ API ํ˜ธ์ถœ์ด ๋ฐœ์ƒ**ํ•˜๊ฑฐ๋‚˜, ๋ฐ์ดํ„ฐ ํ๋ฆ„์ด ๋ถˆ๋ช…ํ™•ํ•ด์ง€๋Š” ๋“ฑ,ย **์œ ์ง€๋ณด์ˆ˜์„ฑ**๊ณผย **๋„คํŠธ์›Œํฌ ์„ฑ๋Šฅ**ย ๋ชจ๋‘์— ์•…์˜ํ–ฅ์„ ๋ผ์ณค๋‹ค. + +์ด๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ดย **SingleMatchCard**,ย **GroupMatchCard**ย ์ปดํฌ๋„ŒํŠธ๋กœ ๊ฐ๊ฐ ์—ญํ• ์„ ๋‚˜๋ˆ„์—ˆ๊ณ , ์ด ๋‘ ์ปดํฌ๋„ŒํŠธ๋Š” ๊ฐ์ž์—๊ฒŒ ๋งž๋Š” API๋‚˜ ๋ฐ์ดํ„ฐ๋งŒ์„ ์ „๋‹ดํ•˜๋„๋ก ํ–ˆ๋‹ค. ์ด์ œย **MatchCardSection**์—์„œ๋Š” ๋‹จ์ˆœํžˆ ๋งค์นญ ํƒ€์ž…์— ๋”ฐ๋ผ ํ•ด๋‹น ์ปดํฌ๋„ŒํŠธ๋ฅผ ์กฐ๊ฑด๋ถ€๋กœ ๋ Œ๋”๋ง๋งŒ ํ•˜๋ฉด ๋˜๋ฏ€๋กœ, ์ปดํฌ๋„ŒํŠธ ๊ตฌ์กฐ๊ฐ€ ๋ช…ํ™•ํ•ด์ง€๊ณ ,ย **ํ›…์ด ๋™์ผํ•œ ์œ„์น˜์—์„œ ํ•œ ๋ฒˆ๋งŒ ํ˜ธ์ถœ**๋˜๋„๋ก ๋ณด์žฅํ•  ์ˆ˜ ์žˆ๋‹ค. + +์ด ๊ตฌ์กฐ์˜ ๊ฐ€์žฅ ํฐ ์žฅ์ ์€ย **API๊ฐ€ ๋ฐ”๋€Œ๊ฑฐ๋‚˜, mock์—์„œ ์‹ค์ œ API๋กœ ์ „ํ™˜ํ•  ๋•Œ ์ปดํฌ๋„ŒํŠธ ํ•˜๋‚˜๋งŒ ์ˆ˜์ •ํ•˜๋ฉด ์ถฉ๋ถ„ํ•˜๋‹ค**๋Š” ์ ์ด๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ์‹ฑ๊ธ€ ๋งค์นญ๋„ ๊ฒฐ๊ตญ API ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ›์•„์˜ค๋Š” ๊ตฌ์กฐ๋กœ ์ „ํ™˜ํ•˜๊ณ  ์‹ถ์„ ๋•Œ, SingleMatchCard๋งŒ ์ˆ˜์ •ํ•˜๋ฉด ๋˜๋ฏ€๋กœย **๋‚ฎ์€ ๊ฒฐํ•ฉ๋„์™€ ๋†’์€ ์‘์ง‘๋ ฅ**์„ ๊ฐ€์ง„๋‹ค. ๋˜ํ•œ,ย **๋ถˆํ•„์š”ํ•œ ๋„คํŠธ์›Œํฌ ์š”์ฒญ์ด ๊ทผ๋ณธ์ ์œผ๋กœ ์ฐจ๋‹จ**๋˜์–ด, ์„œ๋น„์Šค์˜ ๋„คํŠธ์›Œํฌ ํšจ์œจ๊ณผ ์„ฑ๋Šฅ์ด ํฌ๊ฒŒ ๊ฐœ์„ ๋œ๋‹ค. + +**Suspense**๋ฅผ ํ™œ์šฉํ•ด ๋ฐ์ดํ„ฐ ํŽ˜์นญ์ด ๋๋‚œ ํ›„์—๋งŒ ๋ Œ๋”๋ง์ด ์ด๋ฃจ์–ด์ง€๋„๋ก ๋ณด์žฅํ•จ์œผ๋กœ์จ, ํŽ˜์ด์ง€ ์ „ํ™˜ ์‹œ ๋ถˆ์™„์ „ํ•œ ๋ฐ์ดํ„ฐ๋กœ ์ธํ•œ ๊นœ๋นก์ž„์ด๋‚˜ ์Šคํƒ€์ผ ์ด์Šˆ๋„ ๋ง‰์„ ์ˆ˜ ์žˆ๋‹ค. ๋ฐ์ดํ„ฐ ํ๋ฆ„์ด ํƒ€์ž…๋ณ„๋กœ ๋ช…ํ™•ํ•˜๊ฒŒ ๊ตฌ๋ถ„๋˜์–ด ์žˆ์–ด,ย **๋””๋ฒ„๊น…๊ณผ ์ถ”๊ฐ€ ๊ธฐ๋Šฅ ๊ฐœ๋ฐœ์ด ํ›จ์”ฌ ์šฉ์ด**ํ•ด์กŒ๊ณ ,ย **ํ›…์˜ ๊ทœ์น™ ์œ„๋ฐ˜**ย ๋ฌธ์ œ๋„ ์ ˆ๋Œ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š๋Š”๋‹ค. + +์ด์ฒ˜๋Ÿผ,ย **์ฝ”๋“œ๋ฒ ์ด์Šค๊ฐ€ ๋ณต์žกํ•ด์งˆ์ˆ˜๋ก ์ปดํฌ๋„ŒํŠธ์™€ ํ›…์˜ ์—ญํ• ์„ ๋ถ„๋ฆฌ**ํ•˜๋Š” ๊ฒƒ์€ ๋งค์šฐ ์ค‘์š”ํ•˜๋‹ค. ํ›… ๋‚ด๋ถ€์—์„œ ์กฐ๊ฑด๋ถ€ ์ฒ˜๋ฆฌํ•˜๊ธฐ๋ณด๋‹ค๋Š”,ย **์ƒ์œ„ ์ปดํฌ๋„ŒํŠธ์—์„œ ์กฐ๊ฑด๋ถ€ ๋ Œ๋”๋ง**์„ ํ•˜๋Š” ๊ตฌ์กฐ๋ฅผ ํ†ตํ•ด, ๊ฐ๊ฐ์˜ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์ž์‹ ์˜ ๋ฐ์ดํ„ฐ์™€ API, UI์— ๋Œ€ํ•œ ์ฑ…์ž„๋งŒ์„ ๊ฐ€์ง€๋„๋ก ํ•˜๋Š” ๊ฒƒ์ดย **์œ ์ง€๋ณด์ˆ˜์„ฑ, ํ™•์žฅ์„ฑ, ๊ทธ๋ฆฌ๊ณ  ์•ˆ์ •์„ฑ**ย ๋ชจ๋‘๋ฅผ ๋†’์ด๋Š” ํ•ต์‹ฌ์ ์ธ ์›์น™์ž„์„ ๋‹ค์‹œ ํ•œ ๋ฒˆ ๊นจ๋‹ฌ์•˜๋‹ค. \ No newline at end of file diff --git a/docs/trouble/useFunnel.md b/docs/trouble/useFunnel.md new file mode 100644 index 00000000..d63ac883 --- /dev/null +++ b/docs/trouble/useFunnel.md @@ -0,0 +1,103 @@ +### โœ” ๋„์ž…ํ•œ ๊ธฐ์ˆ (๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ)๊ณผ ์ด์œ  (์—†๋‹ค๋ฉด ์ƒ๋žต ๊ฐ€๋Šฅ) + +- `useSearchParams` (react-router-dom) + + โ†’ URL ์ฟผ๋ฆฌ์ŠคํŠธ๋ง์œผ๋กœ ํผ๋„ ๋‹จ๊ณ„๋ฅผ ๊ด€๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด ๋„์ž…ํ–ˆ๋‹ค. ์ƒˆ๋กœ๊ณ ์นจ์ด๋‚˜ ๊ณต์œ  ์‹œ์—๋„ ํ˜„์žฌ ๋‹จ๊ณ„๋ฅผ ์œ ์ง€ํ•  ์ˆ˜ ์žˆ๋‹ค. + +- ์ปค์Šคํ…€ ํ›… `useFunnel` + + โ†’ ํผ๋„ ๋‹จ๊ณ„ ๊ด€๋ฆฌ, ์ด์ „/๋‹ค์Œ ๋‹จ๊ณ„ ์ด๋™, ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ ๋“ฑ์„ ์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ํ˜•ํƒœ๋กœ ๋ถ„๋ฆฌํ•ด ๊ตฌ์กฐํ™”ํ–ˆ๋‹ค. + + +### โœ” ๋ฌธ์ œ ์š”์•ฝ + +ํผ๋„ ๊ตฌ์กฐ์˜ ์˜จ๋ณด๋”ฉ์„ ๊ตฌํ˜„ํ•˜๋ฉด์„œ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ–ˆ๋‹ค: + +1. ์˜จ๋ณด๋”ฉ ๋„์ค‘ ์‚ฌ์šฉ์ž๊ฐ€ '๊ทธ๋ฃน ๋งค์นญ'์„ ์„ ํƒํ–ˆ์„ ๋•Œ, ํผ๋„ ํ๋ฆ„์ด ๊ฐˆ๋ผ์ง€๋Š” ๊ตฌ์กฐ๋ฅผ ์–ด๋–ป๊ฒŒ ์„ค๊ณ„ํ• ์ง€. +2. ํผ๋„ ๋‹จ๊ณ„๋ฅผ ๊ธฐ์ค€์œผ๋กœ ํ”„๋กœ๊ทธ๋ ˆ์Šค ๋ฐ”๋ฅผ ํ‘œ์‹œํ•˜๋ ค ํ–ˆ์œผ๋‚˜, **์ „์ฒด ์Šคํ… ์ˆ˜๊ฐ€ ๋™์ ์œผ๋กœ ๋ฐ”๋€Œ๋Š” ์ƒํ™ฉ์—์„œ ์ง„ํ–‰๋ฅ ์„ ์–ด๋–ป๊ฒŒ ๊ณ„์‚ฐํ• ์ง€**. +3. ์ƒˆ๋กœ๊ณ ์นจ ์‹œ ํ˜„์žฌ ๋‹จ๊ณ„์™€ ์„ ํƒ๊ฐ’์ด ์œ ์ง€๋˜์ง€ ์•Š์•„ **์ง„ํ–‰ ์ค‘์ด๋˜ ์˜จ๋ณด๋”ฉ์ด ์ดˆ๊ธฐํ™”๋˜๋Š” UX ๋ฌธ์ œ**. +4. ์ด๋ฏธ ์˜จ๋ณด๋”ฉ์„ ์™„๋ฃŒํ•œ ์‚ฌ์šฉ์ž๊ฐ€ URL๋กœ ๋‹ค์‹œ ์ ‘์†ํ–ˆ์„ ๋•Œ **์–ด๋–ป๊ฒŒ ์ฒ˜๋ฆฌํ• ์ง€** (์žฌ์ ‘๊ทผ ํ—ˆ์šฉ? ํ™ˆ ๋ฆฌ๋””๋ ‰์…˜? ์—๋Ÿฌ ํŽ˜์ด์ง€?). + +### โœ” ์›์ธ ๋ถ„์„ + +### 1. ํผ๋„์˜ ๋™์  ๋ถ„๊ธฐ ๊ตฌ์กฐ + +์ฒ˜์Œ์—๋Š” ํ•˜๋‚˜์˜ `useFunnel` ํ›… ์•ˆ์—์„œ `MATCHING_TYPE`์— ๋”ฐ๋ผ ๋ถ„๊ธฐ ์ฒ˜๋ฆฌ๋ฅผ ํ•˜๋ ค ํ–ˆ์œผ๋‚˜, + +- ๋ถ„๊ธฐ ์ „์—๋Š” ์ „์ฒด ์Šคํ…์˜ ๊ฐœ์ˆ˜๋ฅผ ์•Œ ์ˆ˜ ์—†์–ด `ProgressBar` ๊ณ„์‚ฐ์— ๋ฌธ์ œ ๋ฐœ์ƒ +- `GROUP_FUNNEL_STEPS`๋Š” `FIRST_FUNNEL_STEPS`์™€ ๊ตฌ์กฐ๋„ ๋‹ค๋ฅด๊ณ , ์ฟผ๋ฆฌ์ŠคํŠธ๋ง๋„ ๋ณ„๋„๋กœ ๊ด€๋ฆฌ๋˜์–ด์•ผ ํ•˜๋ฏ€๋กœ ๊ฒฐ๊ตญ **๋‘ ํผ๋„์„ ๋ถ„๋ฆฌ**ํ•จ + +### 2. ์ƒˆ๋กœ๊ณ ์นจ ์‹œ ์ƒํƒœ ์ดˆ๊ธฐํ™” + +- ์ƒํƒœ(state)๋Š” `useState`๋กœ๋งŒ ๊ด€๋ฆฌ๋˜๊ณ  ์žˆ์—ˆ๊ณ , URL์€ ์ฟผ๋ฆฌ์ŠคํŠธ๋ง์œผ๋กœ ํ˜„์žฌ `step`๋งŒ ์œ ์ง€๋จ +- ์ƒˆ๋กœ๊ณ ์นจ ์‹œ `selections` ๊ฐ์ฒด๊ฐ€ ์ดˆ๊ธฐํ™”๋˜๋ฏ€๋กœ, ์ด์ „์— ์„ ํƒํ–ˆ๋˜ ๊ฐ’๋“ค์ด ๋ชจ๋‘ ์‚ฌ๋ผ์ง โ†’ ํผ๋„ ํ๋ฆ„์ƒ ๋’ค๋กœ ๋Œ์•„๊ฐ€๋„ UX๊ฐ€ ๋ถˆ์•ˆ์ •ํ•ด์ง + +### 3. ์™„๋ฃŒ๋œ ์‚ฌ์šฉ์ž์˜ ์žฌ์ ‘๊ทผ + +- API๋ฅผ ํ†ตํ•ด ์„œ๋ฒ„์— `POST` ์š”์ฒญ์„ ๋ณด๋‚ธ ํ›„, ์‚ฌ์šฉ์ž๊ฐ€ `/onboarding` ์ฃผ์†Œ๋กœ ๋‹ค์‹œ ์ ‘์†ํ•  ์ˆ˜ ์žˆ๋Š” ๊ตฌ์กฐ์˜€์Œ +- ๋‹ค์‹œ ์ ‘์† ์‹œ ์™„๋ฃŒ๋œ ์‚ฌ์šฉ์ž๋„ ์˜จ๋ณด๋”ฉ ํ๋ฆ„์œผ๋กœ ์ง„์ž… ๊ฐ€๋Šฅํ•ด ์˜๋„์น˜ ์•Š์€ ์žฌ์š”์ฒญ ๋˜๋Š” ์ค‘๋ณต ์ž…๋ ฅ์ด ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Œ + +### โœ” ํ•ด๊ฒฐ ๋ฐฉ๋ฒ• + +### 1. ํผ๋„ ๊ตฌ์กฐ ๋ถ„๋ฆฌ ๋ฐ `navigate` ํ™œ์šฉ + +- `MATCHING_TYPE` ๋‹จ๊ณ„์—์„œ "๊ทธ๋ฃน"์„ ์„ ํƒํ•˜๋ฉด `navigate('/onboarding/group?step=GROUP_ROLE')`๋กœ ์ด๋™ +- ์ผ๋ฐ˜ ์˜จ๋ณด๋”ฉ๊ณผ ๊ทธ๋ฃน ์˜จ๋ณด๋”ฉ์„ ์™„์ „ํžˆ **๋‹ค๋ฅธ ํผ๋„ ํ๋ฆ„**์œผ๋กœ ๋ถ„๋ฆฌํ•˜์—ฌ `useFunnel(GROUP_FUNNEL_STEPS)`์„ ๊ฐ๊ฐ ์ ์šฉ +- `goTo`๋ฅผ ํ†ตํ•ด ์ฟผ๋ฆฌ์ŠคํŠธ๋ง๋งŒ ๋ณ€๊ฒฝํ•˜๋ฉฐ ๋‹จ๊ณ„ ์ด๋™ โ†’ ์ƒˆ๋กœ๊ณ ์นจ ํ›„์—๋„ ํ•ด๋‹น ๋‹จ๊ณ„ ์œ ์ง€ ๊ฐ€๋Šฅ + +### 2. `ProgressBar`์™€ ๋™์  ์Šคํ… ์ˆ˜ ์ฒ˜๋ฆฌ + +- ์ผ๋ฐ˜ ํผ๋„์—์„œ๋Š” `ProgressBar currentStep={progressOverride ?? currentIndex}`๋กœ ๊ณ„์‚ฐ +- ๊ทธ๋ฃน ํผ๋„๋กœ ๋ถ„๊ธฐ๋œ ์ดํ›„์—๋Š” `GROUP_FUNNEL_STEPS.length`๋ฅผ ๊ธฐ์ค€์œผ๋กœ ๋ณ„๋„๋กœ `ProgressBar` ๋ Œ๋”๋ง +- `progressOverride` state๋ฅผ ํ†ตํ•ด ์กฐ๊ฑด๋ถ€๋กœ ์˜ค๋ฒ„๋ผ์ด๋”ฉ ๊ฐ€๋Šฅํ•˜๊ฒŒ ๊ตฌํ˜„ + +### 3. ์ƒˆ๋กœ๊ณ ์นจ ์‹œ ๋‹จ๊ณ„ ์œ ์ง€ ๋ฐ ์—๋Ÿฌ ๋ฐฉ์ง€ + +- `useFunnel` ๋‚ด๋ถ€์—์„œ ์ฟผ๋ฆฌ์ŠคํŠธ๋ง(`?step=X`)์ด ์—†๊ฑฐ๋‚˜ ์œ ํšจํ•˜์ง€ ์•Š์„ ๊ฒฝ์šฐ, + + โ†’ `setSearchParams({ step: steps[0] })`์œผ๋กœ ๊ฐ•์ œ ์ดˆ๊ธฐํ™” + + โ†’ ์ž˜๋ชป๋œ ์ ‘๊ทผ์€ `navigate(ROUTES.ERROR)`๋กœ ์—๋Ÿฌ ํŽ˜์ด์ง€ ์œ ๋„ + + +```tsx +useEffect(() => { + if (!stepFromUrl) { + setSearchParams({ step: steps[0] }, { replace: true }); + } + if (!isValidStep) { + navigate(ROUTES.ERROR, { replace: true }); + } +}, [...]); +``` + +### 4. ์™„๋ฃŒ๋œ ์‚ฌ์šฉ์ž์˜ ์žฌ์ ‘๊ทผ ์ฒ˜๋ฆฌ + +- ์„œ๋ฒ„์—์„œ ์ด๋ฏธ ์˜จ๋ณด๋”ฉ์„ ์™„๋ฃŒํ•œ ์‚ฌ์šฉ์ž์˜ ๊ฒฝ์šฐ `/onboarding` ์ ‘์† ์‹œ ํ™ˆ์œผ๋กœ redirect ๋˜๋„๋ก ๊ฐ€๋“œ ํ•„์š” +- ํด๋ผ์ด์–ธํŠธ์—์„œ `GET /my/onboarding-status`์™€ ๊ฐ™์€ API๋ฅผ ํ†ตํ•ด ์ง„ํ–‰ ์—ฌ๋ถ€ ํŒ๋‹จ โ†’ ์ง„์ž… ์ œํ•œํ•˜๊ฑฐ๋‚˜ ์ค‘๊ฐ„๋‹จ๊ณ„์—์„œ redirect ์ฒ˜๋ฆฌ + +### โœ” ํšŒ๊ณ  ๋ฐ ๊ฐœ์„  ๋ฐฉํ–ฅ + +- **ํผ๋„ UI๋Š” ์ •์ ์ธ ํ๋ฆ„์„ ๊ฐ€์ •ํ•˜๋ฉด ์•ˆ ๋  ๊ฒƒ ๊ฐ™๋‹ค.** + + ํŠนํžˆ UX ํ๋ฆ„ ์ƒ ์‚ฌ์šฉ์ž์˜ ์„ ํƒ์— ๋”ฐ๋ผ ๋‹ค์Œ ๋‹จ๊ณ„๊ฐ€ ๋‹ฌ๋ผ์ง€๋Š” ๊ฒฝ์šฐ๊ฐ€ ๋งŽ๊ธฐ ๋•Œ๋ฌธ์—, + + ํผ๋„ ์ „์ฒด ๋‹จ๊ณ„๋ฅผ ํ•˜๋‚˜์˜ ๊ณ ์ •๋œ ๋ฆฌ์ŠคํŠธ๋กœ ์ฒ˜๋ฆฌํ•˜๊ธฐ๋ณด๋‹ค **๋ถ„๊ธฐ๋ณ„ ํผ๋„์„ ๋‚˜๋ˆ„๊ณ  ๊ตฌ์กฐ์ ์œผ๋กœ ๋ถ„๋ฆฌํ•˜๋Š” ๊ฒŒ ์•ˆ์ •์ **์ด์—ˆ๋‹ค. + +- **ProgressBar ๊ณ„์‚ฐ์€ ํผ๋„ ํ๋ฆ„์— ๊ฐ•ํ•˜๊ฒŒ ์˜์กดํ•œ๋‹ค.** + + โ€˜์ „์ฒด ๋‹จ๊ณ„ ์ˆ˜๋ฅผ ์–ด๋””๊นŒ์ง€ ๊ณ„์‚ฐํ•  ๊ฒƒ์ธ๊ฐ€โ€™๋ผ๋Š” ๋ฌธ์ œ๋Š” ๋ถ„๊ธฐ๋ฅผ ํฌํ•จํ•˜๋ฉด ๋” ๋ณต์žกํ•ด์ง€๋ฏ€๋กœ, + + ๋ถ„๊ธฐ๋œ ํผ๋„ ํ๋ฆ„๋งˆ๋‹ค ๊ณ ์œ ํ•œ `useFunnel`์„ ๊ด€๋ฆฌํ•˜๊ณ  `progressOverride` ๋“ฑ์„ ํ™œ์šฉํ•˜๋Š” ์ „๋žต์ด ํšจ๊ณผ์ ์ด์—ˆ๋‹ค. + +- **URL ๊ธฐ๋ฐ˜ ์ƒํƒœ ๊ด€๋ฆฌ์˜ ์žฅ์ ** + + `useSearchParams`๋ฅผ ํ†ตํ•ด ํผ๋„ ๋‹จ๊ณ„๋ฅผ URL์— ๋ช…์‹œํ•œ ๋•๋ถ„์—, ์ƒˆ๋กœ๊ณ ์นจ/๋’ค๋กœ๊ฐ€๊ธฐ/์ง์ ‘ ์ ‘๊ทผ ๋“ฑ์˜ ์‹œ๋‚˜๋ฆฌ์˜ค์—์„œ๋„ ์ƒํƒœ๋ฅผ ์•ˆ์ •์ ์œผ๋กœ ์œ ์ง€ํ•  ์ˆ˜ ์žˆ์—ˆ๋‹ค. + +- **์ƒํƒœ ์œ ์ง€์™€ ์ดˆ๊ธฐํ™”์˜ ๊ท ํ˜• ํ•„์š”** + + selections๋ฅผ ๋กœ์ปฌ์Šคํ† ๋ฆฌ์ง€์— ์ €์žฅํ• ์ง€ ์—ฌ๋ถ€๋Š” ์•„์ง ๋ณด๋ฅ˜ํ–ˆ์ง€๋งŒ, ์ดˆ๊ธฐ์—๋Š” ์™„์ „ํžˆ ์‚ฌ๋ผ์ง€๋Š” UX๊ฐ€ ๋„ˆ๋ฌด ๋ถˆ์นœ์ ˆํ•ด์„œ ์ถ”ํ›„์—๋Š” `step`๋งŒ ์œ ์ง€ํ•˜๊ณ  ๊ฐ’์€ ์ž„์‹œ์ ์œผ๋กœ `sessionStorage`์— ์ €์žฅํ•˜๋Š” ๋ฐฉ์•ˆ์„ ๊ณ ๋ คํ•  ์ˆ˜ ์žˆ์„ ๋“ฏํ•˜๋‹ค. + +- **์ค‘๋ณต ์ ‘๊ทผ ๋ฐฉ์ง€ ํ•„์š”** + + ์ด๋ฏธ ์™„๋ฃŒ๋œ ์‚ฌ์šฉ์ž์˜ `/onboarding` ์žฌ์ ‘๊ทผ ์ด์Šˆ๋Š” ์•„์ง ๋ช…ํ™•ํ•œ UX ๊ธฐ์ค€์ด ์—†๋‹ค๋ฉด ์„œ๋ฒ„์—์„œ ์ง„์ž… ์ œํ•œ flag๋ฅผ ๋‚ด๋ ค์ฃผ๋Š” ๊ตฌ์กฐ๋กœ ์ฒ˜๋ฆฌํ•˜๋Š” ๊ฒƒ์ด ์•ˆ์ „ํ•  ๊ฒƒ ๊ฐ™๋‹ค. \ No newline at end of file