도리쓰에러쓰

[React] shop 홈페이지 기능 완성하기 가이드 본문

코딩애플 (React)/기초수업(코딩애플) - 3

[React] shop 홈페이지 기능 완성하기 가이드

강도리 2022. 2. 1. 20:28

저번 게시물에 이어서 작성하겠습니다. (코드 참고)

 

[React] Redux5 :: useSelector, useDispatch

저번 게시물에 이어서 작성하겠습니다. (코드 참고) [React] Redux4 :: dispatch로 데이터 보내기 저번 게시물에 이어서 작성하겠습니다. (코드 참고) [React] Redux3 :: state와 reducer가 더 필요하다면? 저번..

dori-coding.tistory.com


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
  } 
}

 

- 같은 상품이 있으면 수량 증가만 된 것을 확인할 수 있습니다.

 

Comments