-
Notifications
You must be signed in to change notification settings - Fork 47
[4팀 한선민] Chapter3-2. 디자인 패턴과 함수형 프로그래밍 그리고 상태 관리 설계 #20
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
1lmean
wants to merge
47
commits into
hanghae-plus:main
Choose a base branch
from
1lmean:main
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
localStorage에서 cart 데이터를 불러올 때 배열이 아닌 경우 cart.forEach에서 'is not a function' 에러가 발생하는 문제 수정 - JSON.parse 결과에 Array.isArray 검증 추가 - 배열이 아닌 경우 빈 배열 반환으로 안전하게 처리
- 00-선언형과-함수형-프로그래밍.md: 명령형 vs 선언형, 함수형 프로그래밍 핵심 원칙 - 01-함수형-프로그래밍-기초.md: 액션/계산/데이터 분리, 순수 함수 작성법 - 02-엔티티와-계층-구조.md: 엔티티 개념, models → hooks → components 계층 - 03-React-Hook-패턴.md: useCart, useProducts 등 커스텀 훅 구현 - 04-Compound-Components-패턴.md: 선언적 컴포넌트 API 설계 - 05-전역상태관리-Context-vs-Jotai.md: Context vs Jotai 비교 (심화과제) - 06-과제-구현-가이드.md: 단계별 구현 순서, refactoring(hint) 참고, 체크리스트 - README.md: 문서 인덱스 및 읽는 순서
- models/cart.ts에 순수 함수 9개 추가 - getMaxApplicableDiscount: 최대 적용 가능 할인율 계산 - calculateItemTotal: 개별 아이템 할인 적용 후 총액 - calculateCartTotal: 장바구니 총액 (쿠폰 적용 포함) - getRemainingStock: 남은 재고 계산 - addItemToCart: 장바구니에 상품 추가 - removeItemFromCart: 장바구니에서 상품 제거 - updateCartItemQuantity: 수량 변경 - canAddToCart: 추가 가능 여부 - getTotalItemCount: 총 아이템 개수 - App.tsx에서 순수 함수 import 및 사용 - useState/useEffect 대신 계산된 값 사용 (totalItemCount) - 기존 주석 처리된 코드 제거
- utils/formatter.ts에 순수 함수 3개 추가 - formatPrice: 통화 기호 포맷 (₩10,000) - formatPriceKorean: 한글 포맷 (10,000원) - formatPercentage: 퍼센트 포맷 (10%) - App.tsx에서 비순수 formatPrice 함수 제거 - 관리자 페이지: formatPriceKorean 사용 - 쇼핑몰: formatPrice + 조건부 SOLD OUT 렌더링
- hooks/useDebounce.ts 생성 - 제네릭 타입 지원 - value와 delay를 파라미터로 받아 디바운스된 값 반환 - App.tsx에서 기존 useEffect 디바운스 로직 제거 - useDebounce 훅으로 검색어 디바운스 처리 - 테스트 21개 모두 통과
- constants/index.ts 생성 - ProductWithUI 인터페이스 이동 - initialProducts 초기 상품 데이터 이동 - initialCoupons 초기 쿠폰 데이터 이동 - App.tsx에서 상수 import로 변경 - 데이터와 UI 로직 관심사 분리
- hooks/useProducts.ts 생성 - ProductWithUI 인터페이스 정의 - products 상태 관리 (localStorage 동기화 포함) - addProduct, updateProduct, deleteProduct 함수 - App.tsx에서 useProducts 훅 사용 - 상품 도메인 로직 캡슐화 - 테스트 21개 모두 통과
- hooks/useCoupons.ts 완성 - coupons 상태 관리 (localStorage 동기화 포함) - addCoupon: 쿠폰 추가 (중복 체크, result 반환) - deleteCoupon: 쿠폰 삭제 (result 반환) - getCoupon: 쿠폰 조회 - App.tsx에서 useCoupons 훅 사용 - 래퍼 함수로 notification 처리 분리 - selectedCoupon 상태는 App에서 관리 (cart와 관련) - constants import 제거 (훅 내부에서 사용) - 쿠폰 도메인 로직 캡슐화 - 테스트 21개 모두 통과
- hooks/useCart.ts 생성 - cart 상태 관리 (localStorage 동기화 포함) - selectedCoupon 상태 관리 - addToCart: 장바구니 추가 (재고 체크, result 반환) - removeFromCart: 장바구니 제거 - updateQuantity: 수량 변경 (재고 체크, result 반환) - applyCoupon: 쿠폰 적용 (조건 체크, result 반환) - completeOrder: 주문 완료 (result 반환) - totalItemCount, totals 계산값 제공 - App.tsx에서 useCart 훅 사용 - 래퍼 함수로 notification 처리 분리 - 불필요한 import 및 중복 로직 제거 - 장바구니 도메인 로직 캡슐화 - 테스트 21개 모두 통과
- docs/09-리팩토링-실전-기록.md 생성 - 훅별 리팩토링 문제점과 해결 과정 상세 기록 - 이론적 근거 (순수함수, DRY, SRP, 의존성 주입, Result 패턴) - Cross-Cutting Concerns (notification) 처리 방법 - 핵심 교훈 5가지 정리 - 다음 학습 추천 - docs/README.md 업데이트 - 함수형 프로그래밍 실전 적용 경험 문서화
- hooks/useNotification.ts 생성 - Notification 인터페이스 정의 - notifications 상태 관리 - addNotification: 알림 추가 (자동 제거 포함) - removeNotification: 알림 수동 제거 - clearNotifications: 모든 알림 제거 - autoHideDuration 파라미터로 커스터마이징 가능 - App.tsx에서 useNotification 훅 사용 - 기존 Notification 인터페이스 제거 - 기존 addNotification 함수 제거 - setNotifications 직접 호출 → removeNotification 사용 - 알림 UI 로직 캡슐화 - 테스트 21개 모두 통과
- 8번 섹션 추가: hooks/useNotification.ts - 도메인/범용/UI 훅 분류 기준 - Notification 인터페이스 위치 결정 - setNotifications 직접 사용 문제 해결 - 자동 제거 시간 하드코딩 문제 해결 - useNotification vs Result 패턴 비교 - 핵심 교훈 2개 추가 - 훅 분류를 명확히 (범용/UI/도메인) - 캡슐화 원칙 준수 - 목차 번호 업데이트 (8~10번)
- components/Header.tsx 생성 - 로고, 검색창, 관리자 토글, 장바구니 아이콘 포함 - isAdmin, searchTerm 등 props로 전달받음 - App.tsx에서 Header 컴포넌트 import 및 적용 - UI 컴포넌트 분리로 App.tsx 코드량 감소 (~54줄) - 테스트 21개 모두 통과
- Header.Root: 전체 레이아웃 컨테이너 - Header.Logo: 로고 컴포넌트 - Header.Left: 왼쪽 영역 (로고 + 검색창 슬롯) - Header.Right: 오른쪽 영역 (토글 + 장바구니 슬롯) - Header.AdminToggle: 관리자 토글 버튼 App.tsx에서 조합 방식으로 Header 사용 - 검색창, 장바구니 아이콘은 App에서 children으로 전달 - AdminToggle은 Header 내부에서 관리 - 테스트 21개 모두 통과
- features/main/SearchInput.tsx 생성 - 검색 입력 컴포넌트 분리 - value, onChange props로 상태 관리 위임 - features/main/CartIcon.tsx 생성 - 장바구니 아이콘 컴포넌트 분리 - itemCount, show props로 표시 제어 - features/index.ts 생성 (barrel export) - App.tsx에서 features import 적용 - 테스트 63개 모두 통과
- components/Button.tsx 생성 - reverse: 텍스트만 있는 스타일 지원 - fullWidth: 전체 너비 지원 - size: sm/md/lg 사이즈 지원 - disabled 상태 스타일링 - Header.AdminToggle에 Button 컴포넌트 적용 - App.tsx 장바구니 담기 버튼에 Button 컴포넌트 적용 - 테스트 63개 모두 통과
- pages/MainPage.tsx 생성 - 상품 목록 섹션 (ProductGrid) - 장바구니 사이드바 (CartSidebar) - 쿠폰 선택 섹션 - 결제 정보 섹션 - App.tsx에서 MainPage 컴포넌트 사용 - 불필요한 import 정리 (calculateItemTotal, formatPrice, Button) - 테스트 63개 모두 통과
- features/main/ProductCard.tsx 생성 - 상품 이미지, 뱃지 (BEST, 할인율) - 상품명, 설명, 가격 정보 - 재고 상태 표시 - 장바구니 담기 버튼 - MainPage에서 ProductCard 컴포넌트 사용 - features/index.ts에 ProductCard export 추가 - 테스트 63개 모두 통과
- components/Badge.tsx 생성 - variant: red, orange, yellow, green, blue - position: top-left, top-right, bottom-left, bottom-right - ProductCard에서 Badge 컴포넌트 사용 - BEST 뱃지: variant='red' position='top-right' - 할인율 뱃지: variant='orange' position='top-left' - ProductCard에서 Button 컴포넌트 사용 - 테스트 63개 모두 통과
- md 사이즈: px-4 py-2 text-sm → px-4 py-2 - 원본 장바구니 버튼 스타일과 일치하도록 수정 - 테스트 63개 모두 통과
- MainPage에서 상품 목록 렌더링 로직을 ProductList로 분리 - 개별 상품 카드 렌더링 로직을 ProductItem으로 분리 - Badge, Button 공통 컴포넌트 활용
- MainPage에서 useCart 호출하여 장바구니 상태 관리 - onTotalItemCountChange 콜백으로 App에 totalItemCount 전달 - App에서 useCart 의존성 제거 - 장바구니 관련 notification 래퍼 함수들을 MainPage로 이동
- CartList에서 models/cart.ts의 calculateItemTotal 직접 import - CartItem은 계산된 itemTotal 값을 prop으로 받도록 변경 - MainPage에서 calculateItemTotal prop 전달 제거 - props drilling 감소 및 컴포넌트 응집도 향상
- 쿠폰 선택 + 결제 정보 섹션을 CheckoutSection으로 분리 - MainPage에서 주석 처리된 코드 제거 - ProductCard.tsx 파일 삭제 (ProductItem으로 대체됨) - features/index.ts에 CheckoutSection export 추가
- Toast: 개별 알림 아이템 (onClose 콜백으로 닫기 처리) - ToastContainer: 알림 목록 렌더링 - App에서 ToastContainer 사용하도록 변경
- Admin 관련 상태, 핸들러, UI를 AdminPage로 분리 - App.tsx 773줄 → 83줄로 대폭 감소 - useProducts는 App에서 호출하고 AdminPage에 props로 전달 (상태 공유) - useCoupons는 AdminPage에서 자체 호출 (Admin에서만 수정) - addNotification은 props로 전달
- ProductTable, ProductForm 컴포넌트 분리 - useProductForm 훅으로 폼 상태 관리 추출 - Composition 패턴으로 Props Drilling 완전 제거
- ProductForm을 Root, Title, Fields, Discounts, Actions 등으로 분리
- Context API로 formData 공유하여 Props Drilling 제거
- FormMode 타입 추가로 매직 스트링 제거 ("new" → mode: "create" | "edit")
- CouponList, CouponItem, CouponForm 컴포넌트 분리 - AdminPage 337줄 → 105줄로 간소화 - 각 컴포넌트가 단일 책임 원칙 준수
- useLocalStorage 범용 훅 생성 (localStorage와 React state 동기화) - useCart, useCoupons, useProducts에서 중복 localStorage 로직 제거 - 빈 배열일 때 localStorage에서 삭제하는 로직 포함
- App.tsx에서만 useCoupons 호출하도록 통합 - AdminPage는 props로 coupons, addCoupon, deleteCoupon 전달받음 - 상태 불일치 버그 수정
- Zustand 상태관리 라이브러리 설치 - basic 폴더 구조를 advanced로 복사
- useProductStore: 상품 상태 관리 - useCartStore: 장바구니 상태 관리 - useCouponStore: 쿠폰 상태 관리 - useNotificationStore: 알림 상태 관리
- Store에서 직접 상태 가져오도록 변경 - 불필요한 props 제거 (MainPage: 6개→0개, AdminPage: 8개→0개) - useProductForm을 Store 기반으로 리팩토링 - useProductStore에 initialProducts 추가 - 내부에서 useCartStore, useProductStore 등 호출 개선 효과: - Props 개수 100% 감소 - 결합도 감소 (App에 의존하지 않음) - 재사용성 향상 - 코드 가독성 향상
- CartList, ProductList, CheckoutSection: props 완전 제거 - CouponList, ProductTable: props 대부분 제거 - ProductForm, CouponForm: addNotification props 제거 - MainPage, AdminPage 간소화 주요 변경사항: - CartList: Store에서 cart, removeFromCart, updateQuantity 직접 가져오기 - ProductList: 검색어를 내부에서 관리, filteredProducts 내부 계산 - CheckoutSection: Store에서 모든 상태 및 액션 가져오기 - CouponList: Store에서 coupons, addCoupon, deleteCoupon 가져오기 - ProductTable: products는 Store에서 가져오기 - ProductForm: Context에서 addNotification 제거, Store에서 직접 가져오기 - CouponForm: addNotification props 제거, Store에서 직접 가져오기 개선 효과: - 총 Props 개수: 28개 → 8개 (71% 감소) - MainPage: 118줄 → 20줄 (83% 감소) - AdminPage: 88줄 → 51줄 (42% 감소) - 결합도 감소, 재사용성 향상, 유지보수성 향상
- App.tsx: 1125줄 → 40줄 (96% 감소) - 모든 상태를 Store로 이동 - ToastContainer: Store에서 직접 notifications 가져오기 - CartIcon: show prop 제거, itemCount만 props로 받기 주요 변경사항: - App.tsx에서 모든 useState 제거 (isAdmin만 로컬 상태) - 모든 비즈니스 로직을 Store와 models로 분리 - 컴포넌트 계층 구조 명확화 - ToastContainer: Props 2개 → 0개 - CartIcon: Props 2개 → 1개 개선 효과: - 가독성 향상: 1125줄 → 40줄 - 유지보수성 향상: 각 Store와 컴포넌트 독립적 관리 - 테스트 가능성: 각 컴포넌트와 Store 독립적 테스트 가능 - 재사용성 향상: 각 컴포넌트 독립적으로 재사용 가능 - 성능 최적화: Store 기반으로 필요한 부분만 리렌더링
- Create testSetup.ts for Zustand store reset logic - Move beforeEach/afterEach from test file to testSetup.ts - Zustand stores are global singletons, so they need explicit reset between tests
- CartItem: remove removeFromCart, updateQuantity props, use store directly - ProductItem: remove onAddToCart, remainingStock props, use store directly - CartList/ProductList: simplify by not passing callback props to children Entity components now follow the pattern: - Receive only entity data as props (item, product) - Handle actions internally via Zustand store - This removes props drilling and improves component independence
- Add reset() method to useCartStore, useProductStore, useCouponStore, useNotificationStore
- Fix localStorage test assertions for Zustand persist format ({ state: {...}, version })
- Add documentation for Zustand store test fix
- Refactor App.tsx, MainPage.tsx, CheckoutSection.tsx for store integration
Zustand stores are global singletons, so explicit reset is needed between tests
- Update deploy.yml to use index.advanced.html for 404.html - Add build.rollupOptions.input for advanced entry point in vite.config.ts - Exclude refactoring(hint) folder from TypeScript compilation - Remove unused imports and variables in CartIcon, CheckoutSection - Delete unnecessary copy files (App copy.tsx, main copy.tsx)
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
과제의 핵심취지
과제에서 꼭 알아가길 바라는 점
기본과제
Component에서 비즈니스 로직을 분리하기
비즈니스 로직에서 특정 엔티티만 다루는 계산을 분리하기
뷰데이터와 엔티티데이터의 분리에 대한 이해
entities -> features -> UI 계층에 대한 이해
Component에서 사용되는 Data가 아닌 로직들은 hook으로 옮겨졌나요?
주어진 hook의 책임에 맞도록 코드가 분리가 되었나요?
계산함수는 순수함수로 작성이 되었나요?
특정 Entitiy만 다루는 함수는 분리되어 있나요?
특정 Entitiy만 다루는 Component와 UI를 다루는 Component는 분리되어 있나요?
데이터 흐름에 맞는 계층구조를 이루고 의존성이 맞게 작성이 되었나요?
심화과제
이번 심화과제는 Context나 Jotai를 사용해서 Props drilling을 없애는 것입니다.
어떤 props는 남겨야 하는지, 어떤 props는 제거해야 하는지에 대한 기준을 세워보세요.
Context나 Jotai를 사용하여 상태를 관리하는 방법을 익히고, 이를 통해 컴포넌트 간의 데이터 전달을 효율적으로 처리할 수 있습니다.
Context나 Jotai를 사용해서 전역상태관리를 구축했나요? >> Zustand 사용했습니다.
전역상태관리를 통해 domain custom hook을 적절하게 리팩토링 했나요?
도메인 컴포넌트에 도메인 props는 남기고 props drilling을 유발하는 불필요한 props는 잘 제거했나요?
전체적으로 분리와 재조립이 더 수월해진 결합도가 낮아진 코드가 되었나요?
배포 링크
https://1lmean.github.io/front_7th_chapter3-2/
과제 셀프회고
뭔가 딥다이브하며 ... 공부해보려고 시도해보았으나 워낙 몰랐던 내용이 많아서 또 겉핥기가 됐다는 생각이 들었습니다. 항해 끝나고 이런 내용들 다 정리하려고 하면 아마 머리 터질 것 같은데 진짜 큰일난 것 같습니다.
과제를 하면서 내가 알게된 점, 좋았던 점은 무엇인가요?
1. 함수형 프로그래밍의 핵심: 데이터/계산/액션 분류
이론적인 것들이 항상 잘 와닿지 않는 편인데 적용하려고 노력해보니 감이 조금 왔던것 같습니다.
constants/index.ts(initialProducts, initialCoupons)models/cart.ts(calculateCartTotal, getMaxApplicableDiscount)hooks/useCart.ts,hooks/useProducts.ts핵심 깨달음: 액션을 최소화하고, 가능한 많은 로직을 계산(순수함수)으로 옮겨야 테스트/재사용/이해가 쉬워집니다.
2. 계층 구조와 의존성 방향
3. Result 패턴으로 Cross-Cutting Concerns 처리
Result 패턴이란?
Result 패턴은 함수의 성공/실패를 **예외(Exception)**가 아닌 반환값으로 표현하는 함수형 프로그래밍 패턴입니다.
왜 예외 대신 Result 패턴을 사용하는가?
이 과제에서 Result 패턴을 사용한 이유
기본과제 조건: Context를 사용하지 않고 구현해야 함
문제 상황:
useCoupons훅에서addNotification을 호출하려고 했는데,addNotification은useNotification훅에서 관리되어 접근할 수 없었습니다.해결: Result 패턴으로 결과만 반환하고 App에서 notification 처리
Result 패턴의 장점
비슷한 패턴들
함수형 프로그래밍에서는 비슷한 패턴들이 있습니다:
{ success, message }또는{ success, data }Left<Error>/Right<Value>Some<Value>/None{ success, value }/{ success, error }더 복잡한 프로젝트에서는
neverthrow나fp-ts같은 라이브러리를 사용하면 체이닝, 에러 변환 등이 편리해집니다.4. Props 제거 기준
심화과제에서 어떤 props를 남기고 어떤 props를 제거할지 기준을 세웠습니다:
products,cart,couponsaddToCart,removeFromCartaddNotificationproduct,itemonEdit,onAddNewonClick,onChange5. Zustand vs Redux 비교 경험
실무에서 Redux를 사용해봤지만, 이번에 Zustand를 써보니 훨씬 간결하고 편리했습니다:
6. Zustand 테스트 시 주의사항
Zustand store는 전역 싱글톤이므로 테스트 간에 상태가 공유됩니다.
각 store에
reset메서드를 추가하고beforeEach에서 호출해야 합니다:이번 과제에서 내가 제일 신경 쓴 부분은 무엇인가요?
1. 순수함수 분리와 테스트 가능성
models/cart.ts에 순수함수들을 분리할 때, 모든 의존성을 파라미터로 받도록 했습니다:이렇게 하면 React 없이도 단위 테스트가 가능합니다.
2. 훅의 책임 분리
각 훅이 어떤 상태를 "소유"해야 하는지 고민했습니다:
productsuseProductscouponsuseCouponscartuseCartselectedCouponuseCart처음에
selectedCoupon을useCoupons에 넣었다가, cart 총액 체크가 필요해서useCart로 이동했습니다.3. Props Drilling vs 전역 상태의 균형
모든 props를 제거하는 것이 아니라, 도메인 엔티티 props는 유지했습니다:
4. Compound Components 패턴 적용
저번주 준일 코치님께서 폼 분리 관련해서 Compound Components 패턴을 언급해주셔서
ProductForm에 적용해봤습니다:솔직한 평가: Create와 Edit의 차이가 제목/버튼 텍스트뿐이라 오버엔지니어링이었고 코드가 더 복잡해졌다고는 생각하지만 "언제 이 패턴이 필요한지 배웠다"에 더해 "해당 컴포넌트 설계 패턴을 경험해보았다"는 점에서 의미 있는 경험이었습니다.
적절한 상황: UI가 복잡하고 유연한 조합이 필요할 때 (예: 여러 레이아웃 옵션, 커스텀 섹션 추가 등)
이번 과제를 통해 앞으로 해보고 싶은게 있다면 알려주세요!
1. 테스트 커버리지 강화
Zustand 전역 상태 설계 패턴 더 실험해 보기
productStore,cartStore,couponStore,notificationStore를 도메인별로 분리하는 데 집중했습니다.getState()로 바로 물어보는 대신useEnrichedCartItems처럼 cart + product join 전용 훅)domain/cartService.ts처럼 비즈니스 로직을 store 밖으로 분리)도메인 경계와 store 간 권한 설계
productId,quantity같은 참조 정보만 들고 있게 만드는 구조가 더 낫다고 생각했는데, 적용까지 못한 점이 아쉽습니다.UI 설계 패턴 적용 기준 다듬기 (Compound Components 등)
전역 상태 범위를 결정하는 기준 잡기
searchTerm처럼 “전역으로도, 로컬로도 갈 수 있는 애매한 상태”를 보면서,useState에 남길지리뷰 받고 싶은 내용이나 궁금한 것에 대한 질문 편하게 남겨주세요 :)
1. 훅의 의존성 주입 방식
basic 버전에서
useCart(products)처럼 의존성을 주입받았는데, advanced에서는useProductStore.getState()로 다른 store에 접근했습니다:질문: Zustand에서 store 간 의존성이 있을 때,
getState()방식이 적절한가요? 아니면 다른 패턴이 있나요?2. Compound Components vs 심플한 Props 분기
ProductForm에 Compound Components를 적용했는데, 실제로는 심플한 분기가 더 나았을 것 같습니다:
질문: Compound Components 패턴이 정말 필요한 상황의 기준이 있을까요?
3. 전역 상태 범위 결정 기준
searchTerm을 전역 상태(Store)로 관리할지, 로컬 상태(useState)로 관리할지 고민했습니다. 현재는ProductList내부에서 로컬로 관리 중인데:질문: 어떤 상태를 전역으로 올려야 하는지 판단 기준이 있을까요?
구현 내용 상세
📁 폴더 구조 (Basic)
📁 폴더 구조 (Advanced - Zustand)
📊 Props 제거 통계 (심화과제)
📊 App.tsx 간소화 (심화과제)
상태관리 라이브러리 선택 이유 (Zustand)
왜 Zustand를 선택했는가?
실제 사용 후기
현업에서는 Redux 설정 코드가 많아 유지보수 비용이 컸고, Redux Toolkit까지 혼재되면서 구조가 다소 더러운 상태로 프로젝트를 진행했었는데, Zustand를 사용해보니 create() 기반으로 상태 관리를 간결하게 구성하면서 보일러플레이트를 크게 줄였고, 개발 흐름이 훨씬 단순하고 직관적이라는 생각이 들었습니다.
4팀 코드리뷰
두 가지 라이브러리를 모두 사용해보신 분이 ... 있으실까요.