🤔 React-query 사용 이유
오늘 내가 해볼 것은 DB에 있는 장바구니 수량을 실시간으로 반영해주는 아이콘을 만들 것이다.
원래 같았으면 장바구니 버튼 클릭 시 axios 요청을 통해 수량을 setState 함수에 넣고 state값을 렌더링을 시켜줬을 것이다. 하지만 나는 서버 상태를 비동기적으로 처리 해주면서 server state를 따로 관리를 해주는 react-query를 배웠으니 이를 활용해서 구현 할 것이다.
사용 이유
1. 서버 상태와 데이터 동기화
2. server state와 client state 구분 목적
1️⃣ useQuery를 이용한 커스텀 훅 만들기
우선 고려해야 할 점이 있다. 장바구니 수량은 "장바구니 담기" 버튼을 클릭했을 때만 증가한다. 이 말은 쿼리를 계속 관찰하고 있지 않아도 된다는 점이다. 수동으로 클릭 이벤트가 작동되면 그 때만 쿼리를 관찰하면 된다. 또한 장바구니 아이콘은 로그인을 했을 때만 사용할 수 있는 기능이기 때문에 조건도 설정해줘야 한다. 또한 사용자 마다 장바구니 수량이 다르기 때문에 이런 점도 고민을 했다.
고려할 점.
1. 쿼리를 계속 관찰 할 필요가 없다.
2. 사용자마다 장바구니 수량은 다르다.
3. 로그인 시에만 작동을 한다.
// getCart.ts
// 장바구니 갯수 상태
const useQueryStore = () => {
const token = useFetchToken();
const getCartItemCount = () => {
if (token) {
return axios
.get(`${process.env.REACT_APP_API_KEY}/userAuth/getCart`, {
headers: {
Authorization: `Bearer ${token}`,
},
})
.then((res) => {
return res.data;
});
}
};
return useQuery({
queryKey: ['key'],
queryFn: getCartItemCount,
enabled: false,
});
};
export { useQueryStore };
로그인 여부를 확인하는 커스텀 훅(useFetchToken)을 사용해 토큰 값을 가져온다.
토큰이 있는 경우 axios 요청을 한다. 리턴값으로 장바구니 데이터를 가져온다. 또 useQuery의 옵션값으로 enabled 속성을 false로 해주었다. 그 이유는 쿼리가 자동 실행되지 않고 수동으로 처리 하게 하기 위해서다. 쿼리 요청을 하기 위해서는 refetch() 메소드를 사용해줘야 한다.
2️⃣ 장바구니 버튼 컴포넌트
// 장바구니 담기 버튼 컴포넌트
export default function CartBtn() {
const { productId } = useParams();
const { count } = useCount(); // 제품 수량 상태
const token = useFetchToken(); // 사용자 정보 토큰
const { refetch } = useQueryStore(); // 장바구니 개수 상태 관리
// 장바구니 함수
const onClickCartModal = () => {
if (token) {
// token이 존재하는 경우에만 API 요청을 보냅니다.
axios
.post(
`${process.env.REACT_APP_API_KEY}/userAuth/addCart`,
{
productID: productId,
quantity: count,
},
{
headers: {
Authorization: `Bearer ${token}`,
},
},
)
.then(function (response) {
... // 장바구니 확인 모달
refetch();
});
} else {
// 로그인을 안했을 경우
...
}
};
return (
<>
<_cart onClick={onClickCartModal}>장바구니 담기</_cart>
</>
);
}
로그인이 되어 있을 때만 "장바구니 담기" 버튼을 클릭 시 수량이 증가하도록 만들었다.
로그인이 되어 있으면 확인 모달이 나오고 refetch() 메소드를 통해 아까 만들었던 장바구니 커스텀 훅이 발생된다.
장바구니 커스텀 훅의 리턴값으로 장바구니 목록이 나온다. 목록의 길이를 아이콘 컴포넌트에서 보여줄 것이다.
3️⃣ 장바구니 아이콘 컴포넌트
export default function CartIcon() {
const { data, refetch } = useQueryStore();
const token = useFetchToken();
// 로그인 시 장바구니 수량 확인
useEffect(() => {
refetch();
}, [token, refetch]);
return (
<>
<_shoppingBox className="shoppingBox">
<FaCartShopping
style={{
fontSize: '20px',
marginRight: '5px',
padding: '0px 14px',
color: 'rgb(121, 180, 175)',
}}
/>
{data && data.length > 0 ? (
<_countBox
className="countBox"
position={data.length > 9 ? true : false}
>
{data.length <= 9 ? (
<_count>{data.length}</_count>
) : (
<_count>
9
<FaPlus
style={{ width: '7px', marginLeft: '1px' }}
/>
</_count>
)}
</_countBox>
) : null}
</_shoppingBox>
</>
);
}
조건부 렌더링을 통해 장바구니 수량이 있으면 수량 아이콘을 띄웠고 없으면 null 값을 나타냈다. 그리고 UI를 고려해서 만약 장바구니 수량이 9 이상이면 "9+"처럼 되게 만들었다.
가장 상단에 useEffect를 사용한 이유는 로그인 시 이전에 담아뒀던 장바구니 수량을 바로 확인 시켜주기 위해서다. 따라서 토큰(로그인 시)이 생기면 refetch() 메소드를 통해 장바구니 수량을 가져왔다.
'React' 카테고리의 다른 글
카카오 맵 API를 활용한 강력한 커스텀 훅 만들기 (0) | 2024.03.16 |
---|---|
useInfiniteQuery를 활용한 무한 스크롤 구현하기 (2) | 2024.02.25 |
React - React Router 사용하기 (0) | 2023.05.19 |
React - React.memo (0) | 2023.05.18 |
React - useMemo (0) | 2023.05.18 |