배포링크
https://suhyeon57.github.io/front_6th_chapter2-2/
과제의 핵심취지
- React의 hook 이해하기
- 함수형 프로그래밍에 대한 이해
- 액션과 순수함수의 분리
과제에서 꼭 알아가길 바라는 점
- 엔티티를 다루는 상태와 그렇지 않은 상태 - cart, isCartFull vs isShowPopup
- 엔티티를 다루는 컴포넌트와 훅 - CartItemView, useCart(), useProduct()
- 엔티티를 다루지 않는 컴포넌트와 훅 - Button, useRoute, useEvent 등
- 엔티티를 다루는 함수와 그렇지 않은 함수 - calculateCartTotal(cart) vs capaitalize(str)
기본과제
-
Component에서 비즈니스 로직을 분리하기
-
비즈니스 로직에서 특정 엔티티만 다루는 계산을 분리하기
-
뷰데이터와 엔티티데이터의 분리에 대한 이해
-
entities -> features -> UI 계층에 대한 이해
-
Component에서 사용되는 Data가 아닌 로직들은 hook으로 옮겨졌나요?
-
주어진 hook의 책임에 맞도록 코드가 분리가 되었나요?
-
계산함수는 순수함수로 작성이 되었나요?
-
Component에서 사용되는 Data가 아닌 로직들은 hook으로 옮겨졌나요?
-
주어진 hook의 책임에 맞도록 코드가 분리가 되었나요?
-
계산함수는 순수함수로 작성이 되었나요?
-
특정 Entitiy만 다루는 함수는 분리되어 있나요?
-
특정 Entitiy만 다루는 Component와 UI를 다루는 Component는 분리되어 있나요?
-
데이터 흐름에 맞는 계층구조를 이루고 의존성이 맞게 작성이 되었나요?
심화과제
-
재사용 가능한 Custom UI 컴포넌트를 만들어 보기
-
재사용 가능한 Custom 라이브러리 Hook을 만들어 보기
-
재사용 가능한 Custom 유틸 함수를 만들어 보기
-
그래서 엔티티와는 어떤 다른 계층적 특징을 가지는지 이해하기
-
UI 컴포넌트 계층과 엔티티 컴포넌트의 계층의 성격이 다르다는 것을 이해하고 적용했는가?
-
엔티티 Hook과 라이브러리 훅과의 계층의 성격이 다르다는 것을 이해하고 적용했는가?
-
엔티티 순수함수와 유틸리티 함수의 계층의 성격이 다르다는 것을 이해하고 적용했는가?
과제 셀프회고
-
사이드 이펙트란? --> 프로그래밍에서 어떤 함수나 연산의 수행 결과로 시스템의 상태가 예상치 못하게 변경되는 현상 --> 함수 외부의 상태가 변화 --> 순수 함수는 같은 입력 값에 대해 항상 동일한 결과 반환, 즉 사이드 이펙트를 일으키지 않음
-
순수 함수란? --> 외부 상태 변경이 없고, 입력에만 의존 항상 같은 출력 ex)
function add(a, b) {
return a + b; // 외부에 영향을 주지 않음
}
=> 즉, 사이드 이펙트 일으키지 않음
-
유틸 함수란? --> 반복적으로 사용하는 로직을 재사용 가능하게 만든 작은 함수 --> 일반적으로 계산, 형식 변환, 데이터 가공, 조건 검사 등 작은 단위의 기능을 담당
-
커스텀 훅이란? --> React의 hook을 조합해 만든 함수 --> 재사용 가능한 상태 관리 로직과 사이드 이펙트 처리를 묶은 것 --> 이름은 반드시 use로 시작
<GPT에게 물어본 궁금증> Q. 그 커스텀 훅 안에 있는 함수들이 있잖아, 거기서도 한 번만 쓰이는 함수가 있으면 안돼? A. 커스텀 훅 안에 있는 함수가 한 번만 사용된다고 해도, 그 로직이 역할이 분명하고 의미가 있다면 괜찮다. 목적은 가독성, 유지보수성, 역할 분리야. 재사용성은 중요한 기준이지만, "무조건 여러 번 쓰여야 의미 있는 건 아니다".
- 문제 해결 (의존성 배열)
const setValue = useCallback(
(value: T | ((prev: T) => T)) => {
const valueToStore = value instanceof Function ? value(storedValue) : value;
setStoredValue(valueToStore);
window.localStorage.setItem(key, JSON.stringify(valueToStore));
},
[key, storedValue] //
);
useLocalStorage.ts를 구현할 때 setValue 함수가 storedValue를 의존성으로 가져서 무한루프가 발생하는 문제점이 발생하였다. (처음에 product와 cart를 변경할 때에는 테코가 통과해서 문제점을 알지 못 했다.)
그래서 외부 상태를 참조하지 않고, 함수형 업데이트를 사용하여 의존성 배열에서 storedValue를 제외시켰다.
const setValue = useCallback(
(value: T | ((prev: T) => T)) => {
try {
setStoredValue((prevValue) => {
const valueToStore =
value instanceof Function ? value(prevValue) : value;
if (typeof window !== "undefined" && window.localStorage) {
try {
window.localStorage.setItem(key, JSON.stringify(valueToStore));
} catch (storageError) {
console.warn(
`Error setting localStorage key "${key}":`,
storageError
);
}
}
return valueToStore;
});
} catch (error) {
console.warn(`Error in setValue for key "${key}":`, error);
}
},
[key]
);
🔍 분리 기준 명확히! 📋 훅 (Hook) 분리 기준 상태 관리 + 상태 변경 로직 + React 생명주기 📋 비즈니스 로직 분리 기준 순수 계산 + 조건 판단 + 데이터 변환 (React와 무관)
<GPT와의 대화> Q.
export function addItemToCart(
cart: CartItem[],
product: ProductWithUI
): CartItem[] {
const existingItem = cart.find((item) => item.product.id === product.id);
if (existingItem) {
// 기존 아이템이 있으면 수량 증가
return updateCartItemQuantity(cart, product.id, existingItem.quantity + 1);
}
// 새 아이템 추가
return [...cart, { product, quantity: 1 }];
}
그럼 이건 상태 변경이 아니라 react와 무관하기 때문에 비지니스 로직으로 분리하는거지? 커스텀 훅이 아니라?
A.
// 🏢 비즈니스 로직: "무엇을" "어떻게" 할지
export function addItemToCart(cart: CartItem[], product: ProductWithUI): CartItem[] {
// 장바구니 추가 규칙만 담당
}
// 🎣 React 로직: "언제" "어디서" 상태를 업데이트할지
const useCart = () => {
const [cart, setCart] = useState<CartItem[]>([]);
const addItem = (product: ProductWithUI) => {
const newCart = addItemToCart(cart, product); // 비즈니스 로직 위임
setCart(newCart); // React 상태 관리
};
return { cart, addItem };
};
✅ React와 완전히 독립적 - 순수한 계산 로직 ✅ 비즈니스 규칙에만 집중 - "어떻게 추가할지"만 담당 ✅ 재사용성 극대화 - 어떤 상태 관리든 사용 가능 ✅ 테스트 용이성 - React 환경 없이 단위 테스트 가능 ✅ 함수형 프로그래밍 - 순수함수, 불변성 유지 반면 커스텀 훅은 "React 컴포넌트에서 어떻게 이 로직을 사용할지"에 대한 인터페이스를 제공하는 역할입니다! 🎯
과제를 하면서 내가 제일 신경 쓴 부분은 무엇인가요?
과제를 다시 해보면 더 잘 할 수 있었겠다 아쉬운 점이 있다면 무엇인가요?
리뷰 받고 싶은 내용이나 궁금한 것에 대한 질문 편하게 남겨주세요 :)
리뷰 받고 싶은 내용이나 궁금한 것에 대한 질문
export function isCartEmpty(cart: CartItem[]): boolean {
return cart.length === 0;
}
이 함수는 조건을 판단하기 때문에 cart 비지니스 로직으로 구분하였는데 비지니스 로직인지, 유틸 함수로 구분해야할지 궁금합니다.
저는 과제를 진행할 때 ask 모드로 "여기서 ui를 분리하고 싶어, 진행 방법 알려줘" --> Ai가 답변 --> 복사 붙여넣기
비슷하게 ui를 분리 후 "비지니스 로직을 분리하고 싶어 어떻게 해야 돼?" --> 대답을 보고 "이건 비지니스 로직으로 빠져야 하구나" 하고 비지니스 로직으로 복붙을 하며 진행
에러 발생 --> 에러를 복사해서 ai에게 "이건 뭐야?" --> 답변을 통해 어디서 문제가 왜 발생하는지 확인 후 변경 이런 식으로 진행해 왔습니다.
이렇게 진행하다 보면 손코딩은 별로 없고 그냥 "아 ~ 그렇구나" 라고 하며 지나가게 됩니다. 그러다 문득, 베이직 진행 중 이 방향에 의문이 들어 "다시 처음부터 AI에게 묻지 않고 내 손으로 나눠가며 진행을 해볼까?" 라고 생각했지만, 일단 과제의 통과가 목적이기 때문에 어찌됐든 진행이 되면 넘어갔습니다. (회사에서 deadline 맞추듯이 과제도 똑같이 수행)
이런식으로 하는게 맞는지 고민이 되고, 다음 주차 과제에서는 또 똑같이 이렇게 진행을 해야할지 의문이 듭니다.
과제 피드백
수고했어요 수현. 조금은 쓴 소리가 될 수 있을텐데 필요하다고 생각하니까 채점에 대한 답변을 대신할게요.
"일단 과제의 통과가 목적이기 때문에 어찌됐든 진행이 되면 넘어갔습니다. (회사에서 deadline 맞추듯이 과제도 똑같이 수행) 이런식으로 하는게 맞는지 고민이 되고, 다음 주차 과제에서는 또 똑같이 이렇게 진행을 해야할지 의문이 듭니다."
인간은 본능적으로 위험감지신호가 있어요. 본인이 의문이 들었다는거 자체가 이미 본인도 이게 내심 좋은 방향은 아니란걸 알고 있을거에요. 그리고 이건 개인적인 견해로도 잘못된게 맞다 생각합니다.
그렇다면 과제의 통과보다 학습이 더 중요한가? 라고 물으면 과제의 통과가 더 중요합니다. 왜냐하면 '과제를 통과하지 못했다.' 라는 명백한 증거가 있는데 '나는 혼자서 학습을 했기에 과제를 통과하진 못해지만 나는 공부가 되었어!' 라고 스스로 생각을 하기란 대단히 어렵습니다. 실제로 그게 사실일지라도 현실을 부정한다는건 상당한 자기기만에 가까운 자기 확신이 필요하니까요.
그렇지만 지금의 학습방법은 좋지 않습니다. 실제로 코드를 보았는데에도 거의 비판없이 AI스타일의 코드가 붙여져 있어요. 그런데 정작 AI를 썼다는 그 코드의 퀄리티가 월등하게 좋지 않아요. 심지어 지금 작성해준 회고도 에너지를 들여 잘 작성해졌다고 보기는 어렵네요.
AI는 고점을 높인다기보다는 저점을 높이는 장치입니다. AI의 특성상 사람들이 가장 표준적으로 많이 사용하는 것들 학습해서 대답을 제공해요. 물론 그 컨텐츠 중에서는 학습자료, 논문, 지식등 대단한 지식베이스가 있지만 여전히 AI가 만든 코드는 절대적으로 좋은 수준은 아닙니다.
우리가 지향해야 하는건 아직은 부족한 AI 눈과 손이 되어줄 몸이 아니라, AI의 결과가 평균이상이긴해도 결국 모든 사람이 출발하게 되는 가장 저점이라고 생각하고 그 이상을 어떻게 하면 할 수 있을지를 계속 고민해야 되요.
같은 AI를 사용했지만 사람마다 결과가 달라요. 심지어 회고도 코드도 다릅니다. 그리고 그중에서는 수현이가 작성한 코드보다 좋은 것들이 더 많아요.
혼자서 더 많은 고민을 하라는게 아니에요. AI가 만들어준 결과를 시작으로 뭘 더 잘해야하는지를 다른 사람들의 결과물들을 살펴보고 고민하고 더 나은 결과를 물어보고 해서 지금보다 완성도를 더 올려보세요. 첫번째 말해주는 답이 정답이 아니라 이게 가장 평균적인 결과물이라는 생각으로 더 엔트로피를 높일 생각으로 AI와 함께 질문하고 고찰하고 성찰해보기를 바래요.
AI와 함께 하는 현실을 피할 수는 없을 거에요. 그 답을 알아가는 것도 항해플러스 과정에서 발견해나가기를 바랍니다. 어쩄든 다같이 AI를 써도 나보다 더 결과가 좋은 사람들은 지금 내가 하는것과 뭐가 다를까? 라고 한번 생각으로 해법을 찾아보기를 바래요.
화이팅입니다!