본문 바로가기
모각코

[모각코 9회차] 상품관리 REST API 클론 프로젝트(feat.React)

by moonstal 2022. 8. 30.

목표: 상품관리 REST API 클론 프로젝트

상품추가

App.js

    const [items, setItems] = useState([]); //기본상태
    const handleAddClicked = (id) => {
        //같은 아이디 찾기
        const product = products.find((v) => v.id === id);
        const found = items.find((v) => v.id === id);
        const updatedItems =
        //상품확인...모든속성 복사, 개수 +1/없으면 기존 아이템 반환
        //기존것 복사 + 새로운 상품 추가
        found
            ? items.map((v) => (v.id === id ? { ...v, count: v.count + 1 } : v))
            : [
                ...items,
                {
                ...product,
                count: 1,
                },
            ];
        setItems(updatedItems);
    };

    <ProductList products={products} onAddClick {handleAddClicked} />

ProductList.js

<ul className="list-group products">
  {products.map((v) => (
    <li key={v.id} className="list-group-item d-flex mt-3">
      {/* 
            프로퍼티같으면 ...표현(스프레드연산자) 
            productName={v.productName}
            category={v.category}
            price={v.price}
        */}
      <Product {...v} onAddClick={onAddClick} />
    </li>
  ))}
</ul>

Product.js

export function Product(props) {
  const id = props.id;
  const productName = props.productName;
  const category = props.category;
  const price = props.price;

  const handleAddBtnClicked = (e) => {
    props.onAddClick(id);
  };

return (
    <>
  <div className="col">
    <div className="row text-muted">{category}</div>
    <div className="row">{productName}</div>
    </div>
    <div className="col text-center price">{price}원</div>
    <div className="col text-end action">
    <button
        onClick={handleAddBtnClicked}
        className="btn btn-small btn-outline-dark"
    >
        추가
    </button>
  </div>
 </>
  );

상품목록 가져오기

App.js

//컴포넌트가 렌더링 될 때마다 특정 작업을 실행할 수 있도록 하는 Hook
//비동기작업은 여기서
useEffect(() => {
  axios
    .get("http://localhost:8080/api/v1/products")
    .then((v) => setProducts(v.data));
}, []); //빈배열 딱 한번 실행

주문하기

App.js

const handleOrderSubmit = (order) => {
  if (items.length === 0) {
    alert("아이템을 추가해 주세요!");
  } else {
    axios
      .post("http://localhost:8080/api/v1/orders", {
        email: order.email,
        address: order.address,
        postcode: order.postcode,
        orderItems: items.map((v) => ({
          productId: v.productId,
          category: v.category,
          price: v.price,
          quantity: v.count,
        })),
      })
      .then(
        (v) => alert("주문이 정상적으로 접수되었습니다."),
        (e) => {
          alert("서버 장애");
          console.error(e);
        }
      );
  }
};

<Summary items={items} onOrderSubmit={handleOrderSubmit} />;

Summary.js

export function Summary({ items = [], onOrderSubmit }) {
  const totalPrice = items.reduce(
    (prev, curr) => prev + curr.price * curr.count,
    0
  );
  const [order, setOrder] = useState({ email: "" });
  const handleEmailInputChanged = (e) =>
    setOrder({ ...order, email: e.target.value });
  const handleSubmit = (e) => {
    if (order.address === "" || order.email === "" || order.postcode === "") {
      alert("입력값을 확인해주세요!");
    } else {
      onOrderSubmit(order);
    }
  };

  return (
    <>
      <div>
        <h5 className="m-0 p-0">
          <b>Summary</b>
        </h5>
      </div>
      <hr />
      {items.map((v) => (
        <SummaryItem
          key={v.productId}
          count={v.count}
          productName={v.productName}
        />
      ))}
      <form>
        <div className="mb-3">
          <label htmlFor="email" className="form-label">
            이메일
          </label>
          <input
            type="email"
            className="form-control mb-1"
            id="email"
            value={order.email}
            onChange={handleEmailInputChanged}
          />
        </div>
      </form>
      <div className="row pt-2 pb-2 border-top">
        <h5 className="col">총금액</h5>
        <h5 className="col text-end">{totalPrice}원</h5>
      </div>
      <button className="btn btn-dark col-12" onClick={handleSubmit}>
        결제하기
      </button>
    </>
  );
}

SummaryItem.js

export function SummaryItem({ productName, count }) {
  return (
    <div className="row">
      <h6 className="p-0">
        {productName} <span className="badge bg-dark text-">{count}개</span>
      </h6>
    </div>
  );
}

@프로그래머스 미니 데브코스 & CNU SW Academy 강의 내용 정리