일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- 파이어베이스
- JS
- 비트 연산자
- Component
- Redux
- localstorage
- 자바스크립트
- 알고리즘
- CORS
- TypeScript
- 브라우저
- 컴포넌트
- Frontend
- array
- 리액트
- firebase
- 원티드
- v9
- Reducer
- state
- axios
- 프리온보딩
- 프로그래머스
- JavaScript
- 프론트엔드
- react localStorage
- til
- react
- es6
- 타입스크립트
- Today
- Total
도리쓰에러쓰
[React] shop 홈페이지 기능 완성하기 가이드 본문
저번 게시물에 이어서 작성하겠습니다. (코드 참고)
1. 이미지 클릭 시 각각 상세페이지로 이동하기
- 아래 코드는 Card 컴포넌트입니다.
function Card(props) {
let inventory = useContext(inventoryContext);
return(
<div className='col-md-4'>
<img className="img" src={ 'images/img'+ (props.num + 1) +'.jpg' } />
<h4>{ props.products.title }</h4>
<p>{ props.products.content }</p>
<p>{ props.products.price }</p>
<p>재고 : { inventory[props.num] }</p>
</div>
)
}
1️⃣ 이미지를 클릭하면 각각 상세페이지로 이동하는 onClick 이벤트리스너를 작성하겠습니다.
💡 Card 컴포넌트에 아래 코드와 같이 onClick 이벤트리스너를 작성하면 될까요?
<Card products={a} num={i} key={i} onClick={() => { history.push('/detail/0') }}/>
: 위 코드처럼 작성하면 onClick 이벤트리스너가 작동되지 않습니다. Component는 div가 아니기 때문에 onClick 이벤트리스너 속성을 달아도 동작하지 않을 수 있습니다. 이럴 땐 아래 코드처럼 Card Component를 정의한 곳으로 가서 div에 직접 onClick 이벤트리스너를 작성해주시면 됩니다.
function Card(props) {
let inventory = useContext(inventoryContext);
let history = useHistory();
return(
<div className='col-md-4' onClick={() => { history.push('/detail/' + props.products.id) }}>
<img className="img" src={ 'images/img'+ (props.num + 1) +'.jpg' } />
<h4>{ props.products.title }</h4>
<p>{ props.products.content }</p>
<p>{ props.products.price }</p>
<p>재고 : { inventory[props.products.id] }</p>
</div>
)
}
- 다음 메인 페이지에서 0번째 상품 이미지를 클릭하면
- 상세페이지로 이동되는 것을 확인할 수 있습니다.
2. 장바구니 [+], [-] 버튼 완성하기
- 이전 장바구니 페이지에서 0번째 항목은 [+], [-] 버튼을 클릭하면 수량 변경이 잘 되는데, 1번째 항목에서 [+], [-] 버튼을 클릭하면 0번째 항목 수량이 변경됐었습니다.
- 이건 index.js에 있는 reducer에서 하드코딩으로 0번째 수량이 변경되게 했었기 때문인데요.
* copyArr[0].quan++;
* copyArr[0].quan--;
function reducer(state = basicState, action) {
if( action.type === '항목추가' ) {
// 이전 코드 참고
} else if( action.type === '주문하기' ) {
// 이전 코드 참고
} else if( action.type === '수량증가' ) {
let copyArr = [...state];
copyArr[0].quan++;
return copyArr;
} else if( action.type === '수량감소' ) {
let copyArr = [...state];
copyArr[0].quan--;
return copyArr;
} else {
return state
}
}
- 0번째 데이터의 수량만 변경되는 것이 아닌 1번째 데이터도 수량이 변경되게끔 코드를 수정해보겠습니다.
1️⃣ Cart.js에서 요청 방식 변경하기
- 이전엔 button에서 redux 요청할 땐 아래의 코드처럼 요청했었습니다.
{
state.map((a, i)=>{
return(
<tr key={i}>
<td>{ a.id }</td>
<td>{ a.name }</td>
<td>{ a.quan }</td>
<td>
<button onClick={()=>{ dispatch({ type : '수량증가' }) }}>+</button>
<button onClick={()=>{ dispatch({ type : '수량감소' }) }}>-</button>
</td>
</tr>
)
})
}
- button을 클릭하면 상품의 id 값도 보내지도록 요청 방식을 변경해줍니다.
<button onClick={()=>{ dispatch({ type : '수량증가', data : a.id }) }}>+</button>
<button onClick={()=>{ dispatch({ type : '수량감소', data : a.id }) }}>-</button>
2️⃣ index.js에서 요청할 때 데이터를 보냈던 것을 받아 적용해보겠습니다.
* copyArr[action.data].quan++;
* copyArr[action.data].quan--;
function reducer(state = basicState, action) {
if( action.type === '항목추가' ) {
// 이전 코드 참고
} else if( action.type === '주문하기' ) {
// 이전 코드 참고
} else if( action.type === '수량증가' ) {
let copyArr = [...state];
copyArr[action.data].quan++;
return copyArr;
} else if( action.type === '수량감소' ) {
let copyArr = [...state];
copyArr[action.data].quan--;
return copyArr;
} else {
return state
}
}
- 그럼 아래 사진과 같이 0번째, 1번째 데이터 수량 모두 변경된 것을 확인할 수 있습니다.
3. 상세페이지에서 [주문하기] 버튼 누르면 페이지 내의 상품 추가하게 하기
- 이전엔 상세페이지에서 [주문하기] 버튼을 누르면 임시데이터가 추가되고 있었습니다.
Detail.js에서 [주문하기] 버튼을 클릭하면 하드코딩한 데이터가 추가되도록 작성했기 때문인데요.
<button className='btn btn-danger' onClick={ () => {
inventoryOut();
props.dispatch({
type : '항목추가' ,
payload : {
id : 2,
name : 'Black Jacket',
quan : 1
}
});
history.push('/cart');
} }>주문하기</button>
- [주문하기] 버튼을 클릭하면 현재 상세페이지에서 보이고 있는 상품을 추가하도록 해보겠습니다.
1️⃣ 하드코딩 했던 부분을 App.js에서 props로 가져온 데이터로 변경하기
- 이전에 Detail.js에 아래 코드를 작성한 것이 있는데, 이걸 통해 데이터 전송 방식을 변경해보겠습니다.
let findProduct = props.products.find(function(product) {
return product.id = id;
});
- id와 name을 각각 findProduct.id, findProduct.title로 변경하였습니다.
* 재고 수(quan)는 데이터에 없어서 하드코딩 작성
<button className='btn btn-danger' onClick={ () => {
inventoryOut();
props.dispatch({
type : '항목추가' ,
payload : {
id : findProduct.id,
name : findProduct.title,
quan : 1
}
});
history.push('/cart');
} }>주문하기</button>
- [주문하기] 버튼을 누르면 데이터가 추가된 것을 확인할 수 있습니다.
💡 근데 같은 상품을 계속 주문하면 항목 추가가 되고 있습니다.
같은 상품이 있다면, 항목 추가가 되는 것이 아닌 수량 증가가 되도록 코드를 수정해보겠습니다.
- index.js에서 id가 같은 상품이 state에 있으면 id가 같은 상품의 quan을 1 증가하기
* findIndex() : array 안에서 원하는 데이터의 index값을 찾아주는 함수
function reducer(state = basicState, action) {
if( action.type === '항목추가' ) {
let found = state.findIndex((a) => { return a.id === action.payload.id });
let copyArr = [...state];
if(found >= 0) {
copyArr[found].quan++;
return copyArr;
} else {
copyArr.push(action.payload);
console.log(copyArr);
return copyArr;
}
} else if( action.type === '주문하기' ) {
// 이전 코드 참고
} else if( action.type === '수량증가' ) {
// 이전 코드 참고
} else if( action.type === '수량감소' ) {
// 이전 코드 참고
} else {
return state
}
}
- 같은 상품이 있으면 수량 증가만 된 것을 확인할 수 있습니다.
'코딩애플 (React) > 기초수업(코딩애플) - 3' 카테고리의 다른 글
[React] state 변경함수 사용할 때 주의점 : async (0) | 2022.02.02 |
---|---|
[React] React에서 자주 사용하는 if문 작성패턴 5개 (0) | 2022.02.02 |
[React] Redux5 :: useSelector, useDispatch (0) | 2022.02.01 |
[React] Redux4 :: dispatch로 데이터 보내기 (0) | 2022.02.01 |
[React] Redux3 :: state와 reducer가 더 필요하다면? (0) | 2022.01.31 |