# [[Memoization]] ## πŸ“Œ Brief Summary Memoization(λ©”λͺ¨μ΄μ œμ΄μ…˜)은 μž…λ ₯값이 λ³€κ²½λ˜μ§€ μ•Šμ•˜μ„ λ•Œ 계산 κ²°κ³Όλ‚˜ μ»΄ν¬λ„ŒνŠΈμ˜ λ Œλ”λ§ κ²°κ³Όλ₯Ό μΊμ‹±ν•˜μ—¬ μž¬μ‚¬μš©ν•˜λŠ” μ„±λŠ₯ μ΅œμ ν™” 기법이닀 [1]. Reactμ—μ„œλŠ” `React.memo`, `useMemo`, `useCallback`κ³Ό 같은 APIλ₯Ό 톡해 μˆ˜λ™μœΌλ‘œ μ œμ–΄ν•  수 있으며, λΆˆν•„μš”ν•œ λ¦¬λ Œλ”λ§μ„ λ°©μ§€ν•˜μ—¬ μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ˜ λ°˜μ‘μ„±μ„ ν–₯μƒμ‹œν‚¨λ‹€ [1, 2]. μ΅œκ·Όμ—λŠ” React Compilerλ₯Ό 톡해 λΉŒλ“œ νƒ€μž„μ— μžλ™μœΌλ‘œ 더 μ„Έλ°€ν•œ λ‹¨μœ„μ˜ λ©”λͺ¨μ΄μ œμ΄μ…˜μ„ μ‚½μž…ν•˜μ—¬ μˆ˜λ™ κ΄€λ¦¬μ˜ λ³΅μž‘μ„±μ„ μ€„μ΄λŠ” 방식도 λ„μž…λ˜μ—ˆλ‹€ [2-4]. ## πŸ“– Core Content * **μˆ˜λ™ λ©”λͺ¨μ΄μ œμ΄μ…˜ 기법:** κ°œλ°œμžλŠ” μ»΄ν¬λ„ŒνŠΈ μ „μ²΄μ˜ λ Œλ”λ§ κ²°κ³Όλ₯Ό μΊμ‹±ν•˜κΈ° μœ„ν•΄ `React.memo`λ₯Ό, 계산 λΉ„μš©μ΄ 높은 νŒŒμƒ 데이터(derived data)λ₯Ό μΊμ‹±ν•˜κΈ° μœ„ν•΄ `useMemo`λ₯Ό, ν•¨μˆ˜ μ°Έμ‘°λ₯Ό μΊμ‹±ν•˜κΈ° μœ„ν•΄ `useCallback`을 μ‚¬μš©ν•œλ‹€ [1, 2]. `React.memo()`λŠ” κ³ μ°¨ μ»΄ν¬λ„ŒνŠΈ(HOC)둜 μž‘λ™ν•˜λ©°, μ „λ‹¬λ°›λŠ” prop이 λ³€κ²½λ˜μ§€ μ•ŠμœΌλ©΄ λ Œλ”λ§μ„ κ±΄λ„ˆλ›°κ³  λ§ˆμ§€λ§‰ κ²°κ³Όλ₯Ό μž¬μ‚¬μš©ν•œλ‹€ [5, 6]. * **μ°Έμ‘° μ•ˆμ •μ„±(Reference Stability)κ³Ό 얕은 비ꡐ(Shallow Comparison):** ReactλŠ” λ¦¬λ Œλ”λ§ μ—¬λΆ€λ₯Ό κ²°μ •ν•  λ•Œ prop에 λŒ€ν•΄ 얕은 비ꡐλ₯Ό μˆ˜ν–‰ν•œλ‹€ [7]. λ‚΄μš©μ΄ λ™μΌν•˜λ”λΌλ„ λ§€ λ Œλ”λ§λ§ˆλ‹€ μƒˆλ‘­κ²Œ μƒμ„±λ˜λŠ” κ°μ²΄λ‚˜ 인라인 ν•¨μˆ˜λŠ” μƒˆλ‘œμš΄ 참쑰둜 μΈμ‹λ˜μ–΄ λ©”λͺ¨μ΄μ œμ΄μ…˜μ„ 무λ ₯ν™”ν•œλ‹€ [7-9]. λ”°λΌμ„œ `useMemo`와 `useCallback`은 μ΄λŸ¬ν•œ κ°’κ³Ό ν•¨μˆ˜μ˜ μ°Έμ‘°λ₯Ό μ•ˆμ •μ μœΌλ‘œ μœ μ§€ν•˜μ—¬ ν•˜μœ„ μ»΄ν¬λ„ŒνŠΈμ˜ λΆˆν•„μš”ν•œ λ Œλ”λ§μ„ λ°©μ§€ν•˜λŠ” 데 핡심적인 역할을 ν•œλ‹€ [7, 10]. * **μžλ™ν™”λœ λ©”λͺ¨μ΄μ œμ΄μ…˜ (React Compiler):** React CompilerλŠ” λΉŒλ“œ μ‹œ μ½”λ“œλ₯Ό λΆ„μ„ν•˜κ³  μžλ™μœΌλ‘œ λ©”λͺ¨μ΄μ œμ΄μ…˜ λ‘œμ§μ„ μ‚½μž…ν•˜λŠ” μ΅œμ‹  도ꡬ이닀 [2, 3]. μ»΄ν¬λ„ŒνŠΈ 전체λ₯Ό λž˜ν•‘ν•˜λŠ” κΈ°μ‘΄ μˆ˜λ™ 방식과 달리, κ°œλ³„ JSX μš”μ†Œμ™€ 연산을 λ…λ¦½μ μœΌλ‘œ μΊμ‹±ν•˜λŠ” 더 μ„Έλ°€ν•œ μˆ˜μ€€(granular level)의 μ΅œμ ν™”λ₯Ό μˆ˜ν–‰ν•œλ‹€ [4, 11]. 이λ₯Ό 톡해 κ°œλ°œμžλŠ” λ©”λͺ¨μ΄μ œμ΄μ…˜ μ½”λ“œλ‘œ μΈν•œ ν˜Όλž€ 없이 직관적이고 κΉ”λ”ν•œ React μ½”λ“œλ₯Ό μž‘μ„±ν•  수 μžˆλ‹€ [3, 11]. * **적용 κΈ°μ€€:** λ©”λͺ¨μ΄μ œμ΄μ…˜μ€ 순수 μ»΄ν¬λ„ŒνŠΈμ΄κ±°λ‚˜ λΉˆλ²ˆν•˜κ³  ν”Όν•  수 μ—†λŠ” λ¦¬λ Œλ”λ§μ΄ λ°œμƒν•˜λŠ” 경우, λ³΅μž‘ν•œ DOM을 λ Œλ”λ§ν•˜κ±°λ‚˜ κ°’λΉ„μ‹Ό μ—°μ‚°(μ •λ ¬, 필터링 λ“±)을 μˆ˜ν–‰ν•  λ•Œ μ μš©ν•΄μ•Ό ν•œλ‹€ [6, 12]. μΈ‘μ • 없이 λ¬΄λΆ„λ³„ν•˜κ²Œ μ μš©ν•˜λŠ” 것은 μ§€μ–‘ν•΄μ•Ό ν•˜λ©°, React Profiler 등을 톡해 μ‹€μ§ˆμ μΈ μ„±λŠ₯ μ €ν•˜κ°€ 증λͺ…λ˜μ—ˆμ„ λ•Œλ§Œ μ‚¬μš©ν•΄μ•Ό ν•œλ‹€ [12, 13]. ## βš–οΈ Trade-offs & Caveats * **비ꡐ μ—°μ‚° μ˜€λ²„ν—€λ“œ:** λ©”λͺ¨μ΄μ œμ΄μ…˜μ€ κ³΅μ§œκ°€ μ•„λ‹ˆλ‹€. ReactλŠ” 이전 prop을 μ €μž₯ν•˜κ³ , μƒˆλ‘œμš΄ propκ³Ό λΉ„κ΅ν•˜λ©°, μ—…λ°μ΄νŠΈ μ—¬λΆ€λ₯Ό κ²°μ •ν•˜λŠ” μ˜€λ²„ν—€λ“œλ₯Ό λΆ€λ‹΄ν•΄μ•Ό ν•œλ‹€ [14]. λ Œλ”λ§ μžμ²΄κ°€ λΉ λ₯΄κ³  prop이 자주 λ³€κ²½λ˜λŠ” μ»΄ν¬λ„ŒνŠΈμ˜ 경우, λ©”λͺ¨μ΄μ œμ΄μ…˜μ„ μœ„ν•œ 비ꡐ 단계가 μ‹€μ œ λ Œλ”λ§λ³΄λ‹€ 더 λ§Žμ€ μ»΄ν“¨νŒ… μžμ›μ„ μ†Œλͺ¨ν•  수 μžˆλ‹€ [12, 14]. * **μˆ˜λ™ κ΄€λ¦¬μ˜ ν•œκ³„:** μˆ˜λ™ λ©”λͺ¨μ΄μ œμ΄μ…˜μ€ μ½”λ“œλ₯Ό λ³΅μž‘ν•˜κ²Œ λ§Œλ“€κ³ , 쒅속성 배열을 잘λͺ» κ΄€λ¦¬ν•˜κ±°λ‚˜ 객체 μ°Έμ‘°λ₯Ό μ‹€μˆ˜λ‘œ κ°±μ‹ ν•˜μ—¬ λ©”λͺ¨μ΄μ œμ΄μ…˜ 체인을 κΉ¨λœ¨λ¦¬λŠ” λ“±μ˜ 휴먼 μ—λŸ¬λ₯Ό μœ λ°œν•˜κΈ° 쉽닀 [2, 15]. * **React Compiler의 μ œμ•½ 사항:** * **React κ·œμΉ™μ˜ μ—„κ²©ν•œ μ€€μˆ˜:** μ»΄νŒŒμΌλŸ¬κ°€ μ •μƒμ μœΌλ‘œ μ΅œμ ν™”λ₯Ό μˆ˜ν–‰ν•˜λ €λ©΄ λΆˆλ³€μ„± μœ μ§€, λ Œλ”λ§ 쀑 λΆ€μž‘μš©(Side effects) λ°©μ§€ λ“± "Rules of React"λ₯Ό μ—„κ²©νžˆ 따라야 ν•œλ‹€ [16, 17]. * **μ„œλ“œνŒŒν‹° 라이브러리 ν˜Έν™˜μ„±:** λ§€ λ Œλ”λ§λ§ˆλ‹€ μƒˆλ‘œμš΄ 객체 μ°Έμ‘°λ₯Ό λ°˜ν™˜ν•˜λŠ” μ»€μŠ€ν…€ ν›…(예: TanStack Query의 `useMutation`, React Router의 `useLocation` λ“±)은 컴파일러의 λ©”λͺ¨μ΄μ œμ΄μ…˜ 체인을 λ‹¨μ ˆμ‹œν‚¨λ‹€ [18, 19]. 이 경우 κ²°κ΅­ μˆ˜λ™ λ©”λͺ¨μ΄μ œμ΄μ…˜μ΄ ν•„μš”ν•  수 μžˆλ‹€ [19, 20]. * **디버깅 κ°€μ‹œμ„± μ €ν•˜:** μ»΄νŒŒμΌλŸ¬λŠ” λΈ”λž™λ°•μŠ€μ²˜λŸΌ λ™μž‘ν•˜κΈ° λ•Œλ¬Έμ—, μ»΄ν¬λ„ŒνŠΈκ°€ μ˜ˆμƒμΉ˜ μ•Šκ²Œ λ¦¬λ Œλ”λ§λ  λ•Œ μ΅œμ ν™” μ‹€νŒ¨ 원인을 μ½”λ“œ μƒμ—μ„œ μ¦‰κ°μ μœΌλ‘œ νŒŒμ•…ν•˜κΈ° μ–΄λ ΅λ‹€ [21]. λ˜ν•œ React 개발자 λ„κ΅¬μ˜ 'Memo ✨' λ°°μ§€λŠ” μ»΄νŒŒμΌλŸ¬κ°€ μ½”λ“œλ₯Ό μ²˜λ¦¬ν–ˆμŒμ„ μ˜λ―Έν•  뿐, λŸ°νƒ€μž„μ— μ‹€μ œλ‘œ μ΅œμ ν™”κ°€ μ„±κ³΅ν•˜μ—¬ λ¦¬λ Œλ”λ§μ΄ λ°©μ§€λ˜μ—ˆμŒμ„ 보μž₯ν•˜μ§€ μ•Šμ•„ ν˜Όλ™μ„ 쀄 수 μžˆλ‹€ [18]. ## πŸ”— Knowledge Connections ### Related Concepts #### [μ•„ν‚€ν…μ²˜/기반 기술] - [[React Compiler]] - μ—°κ²° 이유: μˆ˜λ™ λ©”λͺ¨μ΄μ œμ΄μ…˜μ˜ λ³΅μž‘μ„±μ„ 쀄이고 λΉŒλ“œ νƒ€μž„μ— μžλ™μœΌλ‘œ μ„Έλ°€ν•œ λ©”λͺ¨μ΄μ œμ΄μ…˜ λ‘œμ§μ„ μ‚½μž…ν•˜μ—¬ μ„±λŠ₯을 μ΅œμ ν™”ν•˜λŠ” 도ꡬ이닀 [3, 4]. - 이 κ°œλ…μ„ 톡해 더 깊게 이해할 수 μžˆλŠ” λΆ€λΆ„: κ°œλ°œμžκ°€ μˆ˜λ™μœΌλ‘œ μž‘μ„±ν•˜λ˜ `useMemo`와 `useCallback`이 λΉŒλ“œ ν”„λ‘œμ„ΈμŠ€ λ‚΄μ—μ„œ μ–΄λ–»κ²Œ μΆ”μƒν™”λ˜κ³  μ΅œμ ν™”λ˜λŠ”μ§€ νŒŒμ•…ν•  수 μžˆλ‹€ [4, 11, 20]. - [[Shallow Comparison]] (얕은 비ꡐ) - μ—°κ²° 이유: `React.memo`κ°€ λ¦¬λ Œλ”λ§ μ—¬λΆ€λ₯Ό νŒλ‹¨ν•  λ•Œ 기본적으둜 μ‚¬μš©ν•˜λŠ” 평가 방식이닀 [6, 7]. - 이 κ°œλ…μ„ 톡해 더 깊게 이해할 수 μžˆλŠ” λΆ€λΆ„: λ‚΄μš©μ΄ 같은 κ°μ²΄λ‚˜ 인라인 ν•¨μˆ˜κ°€ μ™œ μƒˆλ‘œμš΄ prop으둜 μ·¨κΈ‰λ˜μ–΄ λ©”λͺ¨μ΄μ œμ΄μ…˜μ„ μ‹€νŒ¨ν•˜κ²Œ λ§Œλ“œλŠ”μ§€ κ·Έ 원리λ₯Ό 이해할 수 μžˆλ‹€ [7-9]. #### [κ΅¬ν˜„/ν™œμš© 도ꡬ] - [[React Profiler]] & [[why-did-you-render]] - μ—°κ²° 이유: μ»΄ν¬λ„ŒνŠΈμ˜ λ Œλ”λ§ 횟수, μ†Œμš” μ‹œκ°„, 그리고 λΆˆν•„μš”ν•œ λ Œλ”λ§ 트리거λ₯Ό μ‹λ³„ν•˜μ—¬ λ©”λͺ¨μ΄μ œμ΄μ…˜μ΄ ν•„μš”ν•œ 지점을 μ°Ύμ•„λ‚΄λŠ” 진단 도ꡬ듀이닀 [22-25]. - 이 κ°œλ…μ„ 톡해 더 깊게 이해할 수 μžˆλŠ” λΆ€λΆ„: λ§Ήλͺ©μ μΈ μ΅œμ ν™” λŒ€μ‹  객관적 μΈ‘μ • 데이터에 κΈ°λ°˜ν•œ μ „λž΅μ  λ©”λͺ¨μ΄μ œμ΄μ…˜ 적용 방법을 배울 수 μžˆλ‹€ [13, 26]. ### Deeper Research Questions - React Compiler의 μžλ™ν™”λœ 캐싱 λ©”μ»€λ‹ˆμ¦˜μ€ 기쑴의 μ»΄ν¬λ„ŒνŠΈ 레벨 λ©”λͺ¨μ΄μ œμ΄μ…˜(`React.memo`)κ³Ό 비ꡐ할 λ•Œ, μ–΄λ–»κ²Œ κ°œλ³„ JSX μš”μ†Œ μˆ˜μ€€μ˜ 세밀함(granularity)을 λ‹¬μ„±ν•˜λŠ”κ°€? - `React.memo`에 μ‚¬μš©μž μ •μ˜ 비ꡐ ν•¨μˆ˜(Custom Comparison Function)λ₯Ό μ μš©ν•˜λŠ” κΉŠμ€ 비ꡐ 방식이 얕은 비ꡐ에 λ”°λ₯Έ λ Œλ”λ§ λΉ„μš© μ ˆκ°λ³΄λ‹€ μ„±λŠ₯상 λΆˆλ¦¬ν•΄μ§€λŠ” μž„κ³„μ μ€ 어디인가? - TanStack Queryλ‚˜ Material UI와 같이 λΆˆμ•ˆμ •ν•œ(Unstable) 객체 μ°Έμ‘°λ₯Ό 반볡적으둜 λ°˜ν™˜ν•˜λŠ” 라이브러리λ₯Ό μ‚¬μš©ν•  λ•Œ, React Compiler의 ν•œκ³„λ₯Ό μš°νšŒν•˜κ³  λΆˆν•„μš”ν•œ λ¦¬λ Œλ”λ§μ„ λ§‰λŠ” 졜적의 μ•„ν‚€ν…μ²˜ νŒ¨ν„΄μ€ 무엇인가? - `useCallback`κ³Ό `useMemo`λ₯Ό μ˜€λ‚¨μš©ν•˜μ—¬ μ„±λŠ₯ μ˜€λ²„ν—€λ“œλ₯Ό μœ λ°œν•˜λŠ” μ£Όμš” μ•ˆν‹°νŒ¨ν„΄μ€ 무엇이며, ν”„λ‘œνŒŒμΌλ§μ„ 톡해 λ©”λͺ¨μ΄μ œμ΄μ…˜μ˜ 손읡뢄기점을 μ–΄λ–»κ²Œ νŒλ‹¨ν•  수 μžˆλŠ”κ°€? - React Context API의 μƒνƒœ μ—…λ°μ΄νŠΈλ‘œ λ°œμƒν•˜λŠ” 전역적인 λ¦¬λ Œλ”λ§ 폭포(Re-render Cascade) ν˜„μƒμ„ λ°©μ§€ν•˜κΈ° μœ„ν•΄, Context 뢄리(Splitting)와 λ©”λͺ¨μ΄μ œμ΄μ…˜ 기법을 μ–΄λ–»κ²Œ μ‘°ν•©ν•΄μ•Ό ν•˜λŠ”κ°€? ### Practical Application Contexts - **Implementation:** 계산 λΉ„μš©μ΄ 높은 필터링 λ‘œμ§μ— `useMemo`λ₯Ό μ μš©ν•˜κ³ , ν•˜μœ„μ˜ λ©”λͺ¨μ΄μ œμ΄μ…˜λœ μ»΄ν¬λ„ŒνŠΈλ‘œ μ „λ‹¬λ˜λŠ” 이벀트 ν•Έλ“€λŸ¬μ—λŠ” `useCallback`을 μ μš©ν•΄ μ°Έμ‘° μ•ˆμ •μ„±μ„ 보μž₯ν•œλ‹€ [12, 27]. JSX λ‚΄μ˜ 읡λͺ… ν•¨μˆ˜ μ‚¬μš©μ„ μ§€μ–‘ν•˜μ—¬ λ Œλ”λ§λ§ˆλ‹€ μƒˆλ‘œμš΄ μ°Έμ‘°κ°€ μƒμ„±λ˜λŠ” 것을 λ§‰λŠ”λ‹€ [9, 28]. - **System Design:** ν”„λ‘œμ νŠΈμ— React Compilerλ₯Ό λ„μž…ν•˜κΈ° μ „, μ½”λ“œλ² μ΄μŠ€κ°€ "Rules of React"λ₯Ό μ€€μˆ˜ν•˜λ„λ‘ `eslint-plugin-react-hooks`λ₯Ό μ„€μ •ν•˜μ—¬ λ¦°νŒ…μ„ 톡해 μ½”λ“œλ₯Ό ν†΅μ œν•œλ‹€ [17]. - **Operation / Maintenance:** 지속적인 μ„±λŠ₯ λͺ¨λ‹ˆν„°λ§μ„ μœ„ν•΄ 개발 μ€‘μ—λŠ” React Profiler와 `why-did-you-render`λ₯Ό μ‚¬μš©ν•΄ λΆˆν•„μš”ν•œ λ Œλ”λ§μ„ 작고, ν”„λ‘œλ•μ…˜ ν™˜κ²½μ—μ„œλŠ” INP(Interaction to Next Paint) 같은 Core Web Vitals μ§€ν‘œλ₯Ό 좔적해 λ©”λͺ¨μ΄μ œμ΄μ…˜μ˜ μ‹€μ§ˆμ  이점을 ν™•μΈν•œλ‹€ [22-24, 29]. - **Learning Path:** λ¦¬λ Œλ”λ§μ˜ 4κ°€μ§€ μ£Όμš” 원인(State, Props, Context, Parent Render)을 νŒŒμ•…ν•˜κ³  [30], 얕은 λΉ„κ΅μ˜ 원리λ₯Ό ν•™μŠ΅ν•œ λ’€ `React.memo`, `useMemo`의 μˆ˜λ™ μ μš©λ²•μ„ 거쳐 React Compiler의 λ™μž‘ 원리λ₯Ό μ΄ν•΄ν•˜λŠ” μˆœμ„œλ‘œ ν•™μŠ΅ν•œλ‹€ [3, 7, 30]. - **My Project Relevance:** λ³΅μž‘ν•œ λŒ€μ‹œλ³΄λ“œλ‚˜ 리슀트 λ“±μ—μ„œ 데이터λ₯Ό ν•„ν„°λ§ν•˜κ±°λ‚˜ UI와 μƒν˜Έμž‘μš©ν•  λ•Œ λ°œμƒν•˜λŠ” μ‹¬κ°ν•œ ν™”λ©΄ λŠκΉ€ ν˜„μƒκ³Ό λ©”λͺ¨λ¦¬ λˆ„μˆ˜λ₯Ό ν•΄κ²°ν•˜κΈ° μœ„ν•΄ 이 원리듀을 λ„μž…ν•  수 μžˆλ‹€ [12, 31]. ### Adjacent Topics - [[Code Splitting & Lazy Loading]] - ν™•μž₯ λ°©ν–₯: λ©”λͺ¨μ΄μ œμ΄μ…˜μ΄ λŸ°νƒ€μž„μ— λΆˆν•„μš”ν•œ μ»΄ν¬λ„ŒνŠΈ μž¬λ Œλ”λ§μ„ λ°©μ§€ν•œλ‹€λ©΄, 이 기법은 μ• ν”Œλ¦¬μΌ€μ΄μ…˜ 초기 λ‘œλ“œ μ‹œ JavaScript λ²ˆλ“€ 크기λ₯Ό 쀄여 μ„±λŠ₯을 λŒμ–΄μ˜¬λ¦¬λŠ” λ Œλ”λ§/λ‘œλ”© μ•„ν‚€ν…μ²˜ μ΅œμ ν™” 기법이닀 [7, 32, 33]. - [[State Management Libraries (Zustand/Jotai)]] - ν™•μž₯ λ°©ν–₯: μž¦μ€ μƒνƒœ λ³€κ²½μœΌλ‘œ μΈν•œ Context API의 κ΄‘λ²”μœ„ν•œ λ¦¬λ Œλ”λ§μ„ λ°©μ§€ν•˜κΈ° μœ„ν•΄, λ©”λͺ¨μ΄μ œμ΄μ…˜ λŒ€μ‹  Selector(μ„ νƒμž) νŒ¨ν„΄μ„ μ‚¬μš©ν•˜μ—¬ μƒνƒœμ˜ νŠΉμ • λΆ€λΆ„λ§Œ κ΅¬λ…ν•˜κ²Œ λ§Œλ“œλŠ” λŒ€μ•ˆμ  μƒνƒœ 관리 기법이닀 [34, 35]. - [[Concurrent Rendering]] - ν™•μž₯ λ°©ν–₯: λ©”λͺ¨μ΄μ œμ΄μ…˜μœΌλ‘œλ„ ν•΄κ²°ν•˜κΈ° λ²…μ°¬ 무거운 UI λ Œλ”λ§μ΄ λ°œμƒν•  λ•Œ, `useTransition` 및 `useDeferredValue`λ₯Ό μ‚¬μš©ν•˜μ—¬ λ Œλ”λ§μ˜ μš°μ„ μˆœμœ„λ₯Ό μ‘°μ •ν•˜κ³  UI의 λ°˜μ‘μ„±μ„ μœ μ§€ν•˜λŠ” μ§„λ³΄λœ μ„±λŠ₯ μ΅œμ ν™” 방법둠이닀 [36-38]. --- *Last updated: 2026-04-30*