Developer/PROJECT.React

리액트 프로젝트 5. 제품 상세페이지 form 금액 랜더링 , 장바구니 기능 구현

단님 2024. 7. 2. 11:23
728x90
ProductDetails-ProductForm

 

폼에서 필요한 정보는

내가 선택한 상품에 대한정보 (구매 금액이나 옵션을 불러와야하니까.)

유저에 대한 정보가 필요하다.(유저가 없으면 구매 진행이 되면 안되니까.)

프롭스의 형태로 선택된 상품에 대해 받아오고,

세션스토리지에서 로그인 후 올려준 유저 정보를 가져온다.

 

기본으로 구성된 옵션은 두개였다.

처음엔 "포장 옵션도 갯수 만들어주세요" 라는 팀원의 요구에

충분히 만들 수 있을 거라 생각했는데

생각보다 너무 어려웠다.

값을 추후 저장하여 보내주기도 해야하고 다시 세션에 저장도 해야하니 제대로된 형태를 준비해야했다.

 

    // select 옵션에 대한 state
    const [options, setOptions] = useState({
        contentSelect: '', //왼쪽 옵션값
        packagingSelect: '', // 포장 옵션값
    });

    // 숫자 클릭에 대한 state
    const [btnValue, setBtnValue] = useState({
        contentSelect: 1,   //왼쪽 옵션의 갯수
        packagingSelect: 1, //포장 옵션의 갯수
    });

 

 

객체로 기본값들을 정의 해주고 , 

선택할때마다 옵션 정의 값이 들어가야했는데,

옵션 선택값에 대해 + 해주고 , 

갯수에 대해 * 를 해줘야 했다.

 

select 의 value를 해당 state의 속성으로 정의해주고, (options.pakagingSelect)

name 에는 해당하는 state 속성으로 (pakagingSelect)

 

onchange 이벤트를 통해

SetOptions(...options, select 의 name : select 의 value) 이런식으로 속성 변경을 해줘야 했다.

직접적인 변경은 어렵기 때문에 콜백형식을 이루고 , 변수 사용을 위해 계산된 프로퍼티 형식을 취해줘야 했다.

    const onChangeSelectItems = (e) => {
        const { name, value } = e.target;
        setOptions(it => ({
            ...it,
            [name]: value
        }));
    };

 

갯수에 대한 옵션은 버튼 클릭이벤트로 숫자를 증가시키거나 감소시키는 형식인데,

1보다 작아지면 안되기 때문에 1일때는 현재 값을 넣는 형식으로 넣어주게 되었다.

 

클릭이벤트에서 콜백함수형태로 매개변수로 + 할지 - 할지 나눠주고 진행되었다.

우리는 max수량이 정해지지 않았기 때문에 1보다 작아질때만 처리하면 됬다.

 

    const onClickbtn = (type, name) => {
        if (type === '-') {
            if (btnValue[name] > 1) {
                setBtnValue(it => ({
                    ...it,
                    [name]: btnValue[name] - 1
                }));
            } else {
                setBtnValue(it => ({
                    ...it,
                    [name]: btnValue[name]
                }));
            }
        } else {
            setBtnValue(it => ({
                ...it,
                [name]: btnValue[name] + 1
            }));
        }
    };

 

옵션을 바꾸거나 버튼을 통해 수랑이 변경됬다면 금액이 변경되야 하는 형식을 이뤄야 했다.

이부분은 동기적으로 처리하기 위해 useEffect를 사용하였다.

 

처음에는 값을 어떻게 계산해야하는가에 대해서 너무 머리가 아팠다.

왜냐면 어떤 한 항목이 기본옵션에서도 금액이 추가 되는 부분이 생기고,

포장에 대한 옵션만 생각할수가 없어

이부분을 어떤 값이 들어오던 유동적인 옵션 가격을 만들어 주고싶었지만 , 

시간이 빠듯할것같아 includes 로 먼저 해결을 해놨다.

 

추후에는 문자열을 유동적으로 자르기 위해서는 , 

indexOf 와 slice를 이용하여 가져 올 수 있을 것 같다.

-예제 (indexOf , slice 사용)

const text = "Hello, this is a sample text for slicing.";
const startString = "this";
const endString = "text";

// 시작 문자열의 위치를 찾음
const startIndex = text.indexOf(startString);
if (startIndex !== -1) {
    // 끝 문자열의 위치를 찾음 (끝 문자열의 끝 인덱스를 얻기 위해 length를 더함)
    const endIndex = text.indexOf(endString, startIndex) + endString.length;

    if (endIndex !== -1) {
        // slice 메소드를 사용하여 문자열을 잘라냄
        const slicedText = text.slice(startIndex, endIndex);
        console.log(slicedText); // 출력: "this is a sample text"
    } else {
        console.log("끝 문자열을 찾을 수 없습니다.");
    }
} else {
    console.log("시작 문자열을 찾을 수 없습니다.");
}

 

    // 총 금액을 계산하는 함수
    const calculateTotalPrice = () => {
        if (!selectedProduct) return 0; // 선택된 상품이 없으면 0 반환
        let packageADDprice = 0; // 포장 추가 금액
        let defaultADDprice = 0; // 기본 추가 금액

        // 포장 옵션에 따라 추가 금액 설정
        if (options.packagingSelect.includes('(+2000원)')) {
        .....}
        // 내용 옵션에 따라 추가 금액 설정
        if (options.contentSelect.includes('(+220000)')) {
        ....}

        // 총 금액 계산
        return (selectedProduct.price + defaultADDprice) * btnValue.contentSelect + packageADDprice * btnValue.packagingSelect;
    };

 

공식을 만드는데는 굉장한 시간이 소요되었다...

리액트를 하면서 굉장히 어려웠던 부분은 문법적 오류 , 오타....

미세한 차이가 오류를 발생하는데

데이터 가공시 데이터를 원 까지 표현한것과 원을 표현하지 않은 차이에서

자꾸 값이 달라져서 이유를 찾는데까지 시간이 오래걸렸다..

 

구매하기를 통해 링크를 이동하는데 링크를 이동하면서 프롭스의 형태로 전송할수 있는것이

navigte의 state 속성이였다.

그래서 현재 값들과 총 가격에 대해 정리하여 buy라는 페이지로 전송하게 되었다.

 

useData가 있는지 없는지에 대한 상태를 정의해두고 ,

Data가 있으면 로그인 상태라고 보고 없으면 로그인 하지 않은 상태로 분류하여

구매하기나 장바구니 이동을 막았다.

 

유저 데이터에대한 정보로

우리는 값에 대해 세밀하게 기입해두었다.

그중의 장바구니 배열의 1개를 보면 ,

    {
        productId: 2,
        options: {
            contentSelect: '박물관 키링(신라의 미소)',
            packagingSelect: '굿즈 기본 포장(+0원)'
        },
        quantity: {
            contentSelect: 1,
            packagingSelect: 1
        },
        totalPrice: 20000
    },

 

이런식으로 나와야 했기 때문에 , 

장바구니에 넣을 항목들을 미리 하나 정의해두고

const sendBasket = {
    productId: selectedProduct.id,
    options,
    quantity: btnValue,
    totalPrice
};

 

이 장바구니 데이터를 

업데이트 할 데이터에 넣어주고

const updatedUserData = {
    ...userData,
    mypage: {
        ...userData.mypage,
        basket: [...userData.mypage.basket, sendBasket]
    }
};

 

이 데이터를 세션스토리지에 보내준다.

sessionStorage.setItem('LoginUserInfo', JSON.stringify(updatedUserData));

 

 

동기적으로 처리하기 위한방법으로 나는 useEffect를 많이 썼다.

이값이 바뀔때 이상태값도 바꿔줘 라는 용도로 많이 쓰게 되었는데,

나중에는 promise 형태로 바꿔봐도 재밌을것같다.

세션 스토리지에서 추가 된 것들이 확인 가능.