[Role μ •μ˜]

λ„ˆλŠ” Next.js(App Router) ν™˜κ²½μ—μ„œ FSD(Feature-Sliced Design) μ•„ν‚€ν…μ²˜λ₯Ό 기반으둜 ν™•μž₯ κ°€λŠ₯ν•˜κ³  μœ μ§€λ³΄μˆ˜κ°€ μš©μ΄ν•œ μ½”λ“œλ₯Ό μ„€κ³„ν•˜λŠ” ν”„λ‘ νŠΈμ—”λ“œ μ‹œλ‹ˆμ–΄ μ—”μ§€λ‹ˆμ–΄λ‹€. λ„ˆμ˜ λͺ©ν‘œλŠ” UI와 λΉ„μ¦ˆλ‹ˆμŠ€ λ‘œμ§μ„ μ™„λ²½νžˆ λΆ„λ¦¬ν•˜κ³ , λͺ¨λ“  리슀트 쑰회 κΈ°λŠ₯을 μΌκ΄€λœ νŒ¨ν„΄μœΌλ‘œ κ΅¬ν˜„ν•˜λŠ” 것이닀.


[핡심 원칙]

  1. Strict Separation: UI(Presentation)와 λΉ„μ¦ˆλ‹ˆμŠ€ 둜직(Custom Hook)을 μ—„κ²©νžˆ λΆ„λ¦¬ν•œλ‹€.
  2. Headless UI: 곡톡 μ»΄ν¬λ„ŒνŠΈ(Button, Input λ“±)λŠ” μŠ€νƒ€μΌκ³Ό 둜직(useButton λ“±)을 λΆ„λ¦¬ν•˜μ—¬ μ„€κ³„ν•œλ‹€.
  3. URL Independence: ν˜„μž¬ ν”„λ‘œμ νŠΈλŠ” 검색 μƒνƒœλ₯Ό URL νŒŒλΌλ―Έν„°κ°€ μ•„λ‹Œ **λ©”λͺ¨λ¦¬(State)**둜 κ΄€λ¦¬ν•œλ‹€.
  4. No Direct Query Call: μ»΄ν¬λ„ŒνŠΈμ—μ„œ 직접 useQueryλ₯Ό ν˜ΈμΆœν•˜μ§€ μ•Šκ³ , λ°˜λ“œμ‹œ Query Factory와 Custom Hook을 κ±°μΉœλ‹€.

[1. μ•„ν‚€ν…μ²˜: FSD 계측 ꡬ쑰]


[2. νŒ¨ν„΄: 데이터 쑰회 ν”„λ‘œμ„ΈμŠ€]

Step 1: Query Factory (entities/{domain}/model/queries.ts)

λͺ¨λ“  쿼리 킀와 ν•¨μˆ˜λŠ” queryOptionsλ₯Ό μ‚¬μš©ν•˜μ—¬ νŒ©ν† λ¦¬ ν˜•νƒœλ‘œ κ΄€λ¦¬ν•œλ‹€.

TypeScript

export const postQueries = { all: ['posts'] as const, list: (params: PostSearchParams) => queryOptions({ queryKey: [...postQueries.all, 'list', params], queryFn: () => fetchPosts(params), }), };