Conversation
hyesngy
left a comment
There was a problem hiding this comment.
정말 고생 많으셨습니다! 👏🏻👏🏻👏🏻
이번 주 워크북을 통해 Redux Toolkit과 Zustand 두 가지 상태관리 라이브러리를 모두 다뤄보았습니다. 앞으로 프로젝트 복잡도나 규모에 따라 적절한 상태관리 도구를 선택할 수 있는 안목을 갖추게 되셨으면 좋겠습니다! 👍🏻👍🏻👍🏻
| const initialState: CartState = { | ||
| items: cartItems, | ||
| totalAmount: cartItems.length, | ||
| totalPrice: cartItems.reduce((total, item) => total + Number(item.price), 0), | ||
| }; | ||
|
|
||
| const cartSlice = createSlice({ | ||
| name: 'cart', | ||
| initialState, | ||
| reducers: { | ||
| increaseAmount: (state, action: PayloadAction<string>) => { | ||
| const item = state.items.find(item => item.id === action.payload); | ||
| if (item) { | ||
| item.amount += 1; | ||
| cartSlice.caseReducers.calculateTotals(state); | ||
| } | ||
| }, | ||
| decreaseAmount: (state, action: PayloadAction<string>) => { | ||
| const item = state.items.find(item => item.id === action.payload); | ||
| if (item && item.amount > 1) { | ||
| item.amount -= 1; | ||
| cartSlice.caseReducers.calculateTotals(state); | ||
| } | ||
| }, | ||
| removeItem: (state, action: PayloadAction<string>) => { | ||
| state.items = state.items.filter(item => item.id !== action.payload); | ||
| cartSlice.caseReducers.calculateTotals(state); | ||
| }, | ||
| clearCart: (state) => { | ||
| state.items = []; | ||
| state.totalAmount = 0; | ||
| state.totalPrice = 0; | ||
| }, | ||
| calculateTotals: (state) => { | ||
| state.totalAmount = state.items.reduce((total, item) => total + item.amount, 0); | ||
| state.totalPrice = state.items.reduce((total, item) => total + (Number(item.price) * item.amount), 0); | ||
| } | ||
| }, | ||
| }); |
There was a problem hiding this comment.
현재 cartSlice에서 calculateTotals를 caseReducers로 호출하여 구현하셨는데, 이는 좋은 접근이지만 initialState에서 총합 계산 로직이 중복되고 있습니다.
initialState에서도 calculateTotals 로직을 재사용하도록 리팩토링하면 코드 중복을 제거할 수 있고, 계산 로직이 한 곳에 집중되어 유지보수성이 향상될 것 같습니다!
| import { configureStore } from '@reduxjs/toolkit'; | ||
| import cartReducer from '../slice/cartSlice'; | ||
| import modalReducer from '../slice/modalSlice'; | ||
|
|
||
| export const store = configureStore({ | ||
| reducer: { | ||
| cart: cartReducer, | ||
| modal: modalReducer, | ||
| }, | ||
| }); | ||
|
|
||
| export type RootState = ReturnType<typeof store.getState>; | ||
| export type AppDispatch = typeof store.dispatch; No newline at end of file |
There was a problem hiding this comment.
현재 장바구니 데이터가 새로고침 시 초기화되고 있는데, Redux Toolkit의 redux-persist나 Zustand의 persist 미들웨어를 적용하여, 새로고침 후에도 장바구니 상태가 유지되도록 🚀Challenge 미션에 도전해 보시면 좋겠습니다!
| React.useEffect(() => { | ||
| calculateTotals(); | ||
| }, [items, calculateTotals]); |
There was a problem hiding this comment.
현재 useCartStore에서 각 액션 함수들이 calculateTotals를 자동으로 호출하지 않아 CartPage에서 useEffect를 통해 수동으로 총합을 계산하고 있습니다. 이는 상태 업데이트와 총합 계산이 분리되어 일관성 문제가 발생할 수 있으므로, increaseAmount, decreaseAmount, removeItem, clearCart액션들이 실행될 때마다 자동으로 calculateTotals를 호출하도록 수정하면 더욱 안정적인 상태 관리가 가능할 것 같습니다!
hyesngy
left a comment
There was a problem hiding this comment.
10주차 워크북까지 정말 긴 여정이었습니다.
그동안 모두 고생 많으셨습니다! 👏🏻👏🏻👏🏻 짧지 않은 기간동안 의미 있는 시간이 되었기를 바랍니다.
이제 기본 워크북은 모두 완주하셨지만, 11-12주차 워크북도 도전해보시길 추천드립니다! 11주차에서는 Vercel을 활용한 배포와 CI/CD 구성을 다루고, 12주차에서는 WebSocket을 이용한 실시간 통신과 Cypress를 활용한 E2E 테스트를 다룹니다.
앞으로도 꾸준히 학습하고 성장하시길 응원하며, 데모데이까지 화이팅 입니다! 👍🏻👍🏻👍🏻
There was a problem hiding this comment.
현재 컴포넌트들이 적절히 분리되어 재사용성이 좋게 구성되어 있습니다. 특히 MovieFilter, Input, SelectBox, LanguageSelector 등의 세분화된 컴포넌트 분리가 인상적입니다!
| import HomePage from "./pages/HomePage" | ||
| import MovieModal from "./components/MovieModal" | ||
|
|
||
| function App() { | ||
|
|
||
| return ( | ||
| <> | ||
| <HomePage /> | ||
| <MovieModal /> | ||
| </> | ||
| ) | ||
| } | ||
|
|
||
| export default App |
There was a problem hiding this comment.
현재 App.tsx에서 MovieModal을 최상위에서 항상 렌더링하고 있는데, 이는 모달이 닫혀있을 때도 DOM에 존재하며 불필요한 메모리를 사용하여 비효율적입니다.
예를 들어, {isOpen && <MovieModal />} 형태로 조건부 렌더링하면, 실제로 모달이 열려있을 때만 컴포넌트가 마운트되어 성능이 더 개선될 수 있을 것 같습니다!
또는, 단일 책임 원칙에 따라 모달을 사용하는 곳에서 직접 모달 상태를 관리하는 것도 고려해볼 수 있겠습니다.
📝 미션 번호
9주차 미션 1, 2, 3
📋 구현 사항
📎 스크린샷
bandicam.2025-05-26.14-26-03-925.mp4
✅ 체크리스트
🤔 질문 사항