상세 페이지에서 상품 옵션 선택 : 상품 옵션을 선택할 때마다 선택한 옵션을 화면에 추가로 보여주기 위해 옵션을 useState로 두고 값이 업데이트 될 때마다 화면에 반영시켰다.
장바구니 : 장바구니에 정보는 변동이 잦고 서버에 저장해야 할 정도로 의미있는 데이터는 아니라는 판단 하에 로컬스토리지에 저장하는 방식을 택했다.
//Detail.js
...
const [options, setOption] = React.useState([]);
const [sum, setSum] = React.useState(0);
//상품 옵션을 선택하면 화면에 elements 추가 렌더링
const selectOption = (e) => {
const _options = options.filter((o, idx) => {
if (o !== e.target.value) {
return o;
}
});
let price = Number(e.target.value.slice(-7, -1).split(",").join("").trim());
setOption([
..._options,
{ text: e.target.value, num: 1, prd: prd, sum: price },
]);
setSum(sum + price);
};
[상품{상품옵션1{text, num}, 상품옵션{text, num}}, 상품2{상품2의옵션1{text, num}, 상품2의옵션2{text, num}}]
{options && //선택한 옵션이 존재할 때 화면 렌더링
options.map((option, idx) => {
return (
<Grid padding="16px" key={idx}>
<Grid
bg="rgb(248, 248, 248)"
height="98px"
padding="16px"
>
<Grid is_flex padding="0 0 14px 0">
<Text margin="0" size="13px">
{option.text.includes("[") ? (
<H>[{option.text.split("[")[1].split("]")[0]}]</H>
) : null}
{option.text.split("[")[0].split("(")[0]}
</Text>
<svg
onClick={() => {
deleteOption(option);
}}
class="css-1jd8bf1"
xmlns="http://www.w3.org/2000/svg"
width="12"
height="12"
viewBox="0 0 12 12"
>
<g
fill="none"
fill-rule="evenodd"
stroke="#C4C4C4"
stroke-linecap="square"
>
<path
d="M0 0L10.5 10.5"
transform="translate(.75 .75)"
></path>
<path
d="M0 0L10.5 10.5"
transform="translate(.75 .75) matrix(-1 0 0 1 10.5 0)"
></path>
</g>
</svg>
</Grid>
<Grid height="28px" is_flex center>
<Grid is_flex width="116px">
<Grid
_onClick={() => {
minusQuantity(option);
}}
width="28px"
height="28px"
bg="rgb(255, 255, 255)"
>
-
</Grid>
<Grid
width="50px"
height="28px"
bg="rgb(255, 255, 255)"
margin="0 5px"
>
{option.num ? option.num : 1}
</Grid>
<Grid
_onClick={() => {
plusQuantity(option);
}}
width="28px"
height="28px"
bg="rgb(255, 255, 255)"
>
+
</Grid>
</Grid>
<Text margin="0" size="14px">
{Number(
option.text
.slice(-7, -1)
.split(",")
.join("")
.trim()
) * option.num}
</Text>
</Grid>
</Grid>
</Grid>
);
})}
//선택한 옵션의 수량 변경 시 수량 및 가격 반영
const plusQuantity = (option) => {
let price = Number(option.text.slice(-7, -1).split(",").join("").trim());
setSum(sum + price);
option.num += 1;
option.sum += price;
};
const minusQuantity = (option) => {
if (sum > 0 && option.num > 1) {
let price = Number(option.text.slice(-7, -1).split(",").join("").trim());
setSum(sum - price);
option.num -= 1;
option.sum -= price;
}
}; //옵션 삭제
const deleteOption = (target) => {
const _options = options.filter((option, idx) => {
if (option.text !== target.text) {
return option;
}
setSum(
sum -
Number(target.text.slice(-7, -1).split(",").join("").trim()) *
option.num
);
});
setOption(_options);
};
//장바구니 담기 시 로컬 스토리지에 정보를 저장
const setLocalStorage = () => {
const _cart = localStorage.getItem("cart");
if (_cart) {
const parseCart = JSON.parse(_cart);
localStorage.setItem("cart", JSON.stringify([...parseCart, ...options]));
} else {
localStorage.setItem("cart", JSON.stringify(options));
}
//저장 여부를 알리고 페이지 이동 의사를 묻는 알림창
swal({
title: "장바구니에 잘 담겼어요!",
icon: "success",
buttons: {
showCart: { text: "장바구니 이동", value: "showCart" },
cancel: "쇼핑 계속하기",
},
}).then((value) => {
switch (value) {
case "showCart":
history.push("/cart");
break;
}
});
localStorage.getItem("cart")
의 문제점 : 원하는 자료 형태로 저장이 되지 않아 애를 먹었다. 로컬스토리지에서 가져온 기존에 저장되어 있던 상품 정보를 스프레드 문법으로 나누니 배열 안에 딕셔너리대로 나뉘는 것이 아니라 문자열 하나하나로 나누어 지는 것이 아니겠는가. 알고보니 JSON.stringify를 통해 문자열화되어 로컬스토리지에 저장되었기 때문에 getItem을 해왔을 때도 문자열 형태였던 것이다. 원래의 형태인 배열의 특성을 이용하여 가공하기 위해서는 JSON.parse 절차를 반드시 거쳐야 했다! 덕분에 로컬스토리지의 특성을 잘 알게 되었다.