일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- redux상태유지
- UI
- for~in/for~of
- https://lo-victoria.com/introduction-to-redux-toolkit-for-beginners
- 자바스크립트#조건문#문자열
- User Flow
- dom
- @redux-toolkit
- CSS
- Beesbeesbees
- https://dasima.xyz/%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%EC%A0%9C%EA%B3%B1-math-pow-%EA%B3%84%EC%82%B0/
- react
- 자바스크립트#JS#slice#splice
- 자바스크립트#JS#var#let#const#undefined#null
- removeCookie
- 내장고차함수
- 헷갈린다~
- https://developer-talk.tistory.com/299
- 노드교과서
- js
- toString#String
- ㄷㅌ
- slice/splice/split
- JS#3일차달리자#초반인데#시간금방~
- cmarket
- 자바스크립트
- variable#function
- children vs childrenNodes
- UX
- https://www.daleseo.com/js-array-slice-splice/
- Today
- Total
Daily Front_Minhhk
[React] Props Drilling + Cmarket Hooks 본문
Props Drilling이란
Props Drilling은 상위 컴포넌트의 state를 props를 통해 전달하고자 하는 컴포넌트로 전달하기 위해 그 사이는 props를 전달하는 용도로만 쓰이는 컴포넌트들을 거치면서 데이터를 전달하는 현상을 의미합니다. 위 그림처럼 컴포넌트 A의 state를 컴포넌트 D로 전달하기 위해선 사이에 있는 컴포넌트 B, C를 거쳐야합니다.
Props Drilling의 문제점
Props의 전달 횟수가 5회 이내로 많지 않다면 Props Drilling 은 큰 문제가 되지 않습니다. 하지만 규모가 커지고 구조가 복잡해지면서 Props의 전달 과정이 늘어난다면 아래와 같은 문제가 발생합니다.
- 코드의 가독성이 매우 나빠지게 됩니다.
- 코드의 유지보수 또한 힘들어지게 됩니다.
- state 변경시 Props 전달 과정에서 불필요하게 관여된 컴포넌트들 또한 리렌더링이 발생합니다. 따라서, 웹성능에 악영향을 줄 수 있습니다.
상태관리 라이브러리를 사용하게 되면 전역으로 관리하는 저장소에서 직접 state를 꺼내쓸 수 있기 때문에 Props Drilling을 방지하기에 매우 효과적
다양한 상태관리 라이브러리(Redux, Context api, Mobx, Recoil 등) 중 Redux!
Bare minimum requirements
- 쇼핑몰 애플리케이션의 주요 기능을 구현
- [장바구니 담기] 버튼을 이용해 장바구니에 해당 상품이 추가되도록 구현
- 장바구니 내 [삭제] 버튼을 이용해 장바구니의 상품이 제거되도록 구현
- 장바구니 내에서 각 아이템 개수를 변경할 수 있도록 구현
- 장바구니의 상품 개수의 변동이 생길 때마다, 상단 내비게이션 바에 상품 개수가 업데이트 되도록 구현
페이지 전환
페이지 전환은 react-router-dom 이용해 Client Side Routing을 구현
페이지가 전환되지 않는 Single Page App임에도 주소창이 변화
- <App> 루트 컴포넌트
- <Router>, <Routes>, <Route>
- <Nav> 내비게이션 바
- SPA 내에서 화면 전환에 따라 URL를 업데이트하기 위해 <Link> 컴포넌트를 사용
🔥 우선 간단하게 컴포넌트 구조와, 데이터 흐름을 먼저 나타내었다
app.js
function App() {
// 아이템
const [items, setItems] = useState(initialState.items);
// default 장바구니 수량
const [cartItems, setCartItems] = useState(initialState.cartItems);
return (
<Router>
{/* nav 탭 장바구니 수량 props */}
<Nav cartItems={cartItems} />
<Routes>
{/* cartItems, setCartItems props */}
<Route
path="/"
element={
<ItemListContainer
cartItems={cartItems}
setCartItems={setCartItems}
items={items}
/>
}
/>
{/* cartItems, setCartItems props */}
<Route
path="/shoppingcart"
element={
<ShoppingCart
cartItems={cartItems}
setCartItems={setCartItems}
items={items}
/>
}
/>
</Routes>
<img
id="logo_foot"
src={`${process.env.PUBLIC_URL}/codestates-logo.png`}
alt="logo_foot"
/>
</Router>
);
}
ItemListContain.js
item.js 에서 장바구니 담기 버튼에
➡️ onClick={(e) => handleClick(e, item.id)}
이 인자 두개를 넘겨 준다는 것을 확인!
<button *className*="item-button" *onClick*={(e) => handleClick(e, item.id)}>장바구니 담기</button>
1. find() 사용
function ItemListContainer({ items, cartItems, setCartItems }) {
if (!cartItems.find((el) => el.itemId === itemId)) {
setCartItems([
...cartItems,
{
itemId: itemId,
quantity: 1,
},
]);
}
}
2. findIndex() 사용 (장바구니추가 클릭 할 때, 장바구니 페이지에서 수량이 누적됨)
function ItemListContainer({ items, cartItems, setCartItems }) {
const handleClick = (e, id) => {
let findIdx = cartItems.findIndex((e) => e.itemId === id);
if (findIdx !== -1) {
cartItems[findIdx].quantity += 1;
setCartItems(cartItems);
} else {
setCartItems([...cartItems, { itemId: id, quantity: 1 }]);
}
};
클릭을 하면 클릭한 값의 id를 가져와서
→
if 클릭한 값과 현재 있는 값의 id 를 비교해서 존재하면 quantity += 1 해주고
→
else 없으면 새로운 값을 기존 cartItems에 이어서
id값과 수량 1개를 셋팅 해준다.
ShoppingCart.js
export default function ShoppingCart({ items, cartItems, setCartItems }) {
const [checkedItems, setCheckedItems] = useState(
cartItems.map((el) => el.itemId)
);
// 체크
const handleCheckChange = (checked, id) => {
if (checked) {
setCheckedItems([...checkedItems, id]);
} else {
setCheckedItems(checkedItems.filter((el) => el !== id));
}
};
// 올 체크
const handleAllCheck = (checked) => {
if (checked) {
setCheckedItems(cartItems.map((el) => el.itemId));
} else {
setCheckedItems([]);
}
};
//TODO : 장바구니 수량 상태 반영 해주기?
const handleQuantityChange = (quantity, itemId) => {
//* 기존 아이템
const item = [...cartItems];
//* findIndex()로 인덱스 번호 찾고 -> item[인덱스번호].수량 === 수량
const findIdx = cartItems.findIndex((el) => el.itemId === itemId);
item[findIdx].quantity = quantity;
//* useState로 cartItem 상태업뎃ㄱㄱ
setCartItems(item);
};
//TODO : 체크 해제 + 삭제 버튼 눌렀을 때 아이템 삭제
const handleDelete = (itemId) => {
//* 체크 해제
setCheckedItems(checkedItems.filter((el) => el !== itemId));
//* 삭제 버튼
setCartItems(cartItems.filter((el) => el.itemId !== itemId));
};
...생략
}
➡️ 장바구니 삭제버튼
setCartItems(cartItems.filter((el) => el.itemId !== itemId));
➡️ 장바구니 수량변경
- findIndex()
const handleQuantityChange = (quantity, itemId) => {
//* 기존 아이템
const item = [...cartItems];
//* findIndex()로 인덱스 번호 찾고 -> item[인덱스번호].수량 === 수량
const findIdx = cartItems.findIndex((el) => el.itemId === itemId);
item[findIdx].quantity = quantity;
//* useState로 set~ cartItem 상태업뎃ㄱㄱ
setCartItems(item);
};
- map()
const handleQuantityChange = (quantity, itemId) => {
setCartItems(
cartItems.map((el) => {
if (el.itemId === itemId) {
return {
itemId: itemId,
quantity: quantity,
};
} else {
return el;
}
})
);
};
…
assets/state.js 파일,,
App.js → ShoppingCart.js → props 전달 된 cartItems
"cartItems": [
{
"itemId": 1,
"quantity": 1
},
{
"itemId": 5,
"quantity": 7
},
{
"itemId": 2,
"quantity": 3
}
]
Nav.js
function Nav({cartItems}) {
return (
<div id="nav-body">
<span id="title">
<img id="logo" src="../logo.png" alt="logo" />
<span id="name">CMarket</span>
</span>
<div id="menu">
<Link to="/">상품리스트</Link>
<Link to="/shoppingcart">
{/* app.js 에서 cartItems props -> 길이로 수량 확인 */}
장바구니<span id="nav-item-counter">{cartItems.length}</span>
</Link>
</div>
</div>
);
}
Nav({cartItems}) 로 props 받아와서 전달~
장바구니 옆 숫자 표시!!
<span id="nav-item-counter">{cartItems.length}</span>
장바구니 옆 <span>에
{cartItems.length} 로 나타내어 수량을 표현 해준다.
구현된 장바구니,,
💡 장바구니의 전체적인 로직을 다 짜지는 못했다.
체크, 모두체크 등등 많이 있었지만 이번 챕터의 목표는 props로 받은 값을 하위 컴포넌트에 전달하여 값을 이용하는 것 이었다.
다음은 redux로 리팩토링이 예상이 되는데,,, 힘내보자!
상품리스트 페이지
장바구니 페이지
'Code개발일지' 카테고리의 다른 글
[Redux] Cmarket Redux (0) | 2022.12.30 |
---|---|
[Redux] Store, Reducer, Action, Dispatch // Hooks : useDispatch, useSelector (0) | 2022.12.29 |
[React] React Custom Component (0) | 2022.12.26 |
[React] Custom Component (0) | 2022.12.22 |
[Figma] 단축키,, 당근마켓 앱 lo-fi clone (0) | 2022.12.21 |