import { useNavigate } from 'react-router-dom';
import { toast } from 'react-toastify';
import { getUserInfo } from '@/storage/userInfo';
import { PATH } from '@/constants/path';
import order from '@/api/order';
import { renderOrderSuccessToast } from '@/utils/toastContents';
import type { OrderRequest } from '@/api/order';
interface UseOrderSubmitParams {
product: { id: number; name: string; price: number };
count: number;
receiverRef: React.MutableRefObject<{ name: string; phone: string; count: number }[] | null>;
}
export default function useOrderSubmit({ product, count, receiverRef }: UseOrderSubmitParams) {
const navigate = useNavigate();
return async (data: any) => {
const userInfo = getUserInfo();
const token = userInfo?.authToken;
if (!token) {
toast.error('로그인이 필요합니다.');
navigate(PATH.LOGIN);
return;
}
if (!receiverRef.current || receiverRef.current.length === 0) {
toast.error('받는 사람 정보를 입력해주세요.');
return;
}
const { textMessage, senderName, messageCardId } = data;
const orderData: OrderRequest = {
productId: product.id,
message: textMessage,
messageCardId: String(messageCardId),
ordererName: senderName,
receivers: receiverRef.current.map(({ name, phone, count }) => ({
name,
phoneNumber: phone,
quantity: Number(count),
})),
};
try {
const result = await order(orderData);
if (result.data?.success) {
toast(renderOrderSuccessToast(product.name, count, senderName, textMessage), {
type: 'success',
autoClose: 3000,
style: { width: '400px' },
});
navigate(PATH.HOME);
}
} catch (error) {
toast.error(error instanceof Error ? error.message : '주문 중 오류가 발생했습니다.');
}
};
}
위 코드는 react query 없이 작성한 코드이다.
가장 아래 부분의 try catch를 useMutation을 사용해서 바꿀 것이다.
import { useNavigate } from 'react-router-dom';
import { toast } from 'react-toastify';
import { getUserInfo } from '@/storage/userInfo';
import { PATH } from '@/constants/path';
import order from '@/api/order';
import { renderOrderSuccessToast } from '@/utils/toastContents';
import type { OrderRequest } from '@/api/order';
import { useMutation } from '@tanstack/react-query';
interface UseOrderSubmitParams {
product: { id: number; name: string; price: number };
count: number;
receiverRef: React.MutableRefObject<{ name: string; phone: string; count: number }[] | null>;
}
export default function useOrderSubmit({ product, count, receiverRef }: UseOrderSubmitParams) {
const navigate = useNavigate();
const mutation = useMutation({
mutationFn: (orderData: OrderRequest) => order(orderData),
onSuccess: (_, variables) => {
toast(
renderOrderSuccessToast(
product.name,
count,
variables.ordererName,
variables.message
),
{
type: 'success',
autoClose: 3000,
style: { width: '400px' },
},
);
navigate(PATH.HOME);
},
onError: (error) => {
toast.error(error instanceof Error ? error.message : '주문 중 오류가 발생했습니다.');
},
});
return async (data: {
textMessage: string;
senderName: string;
messageCardId: string | number;
}) => {
const userInfo = getUserInfo();
const token = userInfo?.authToken;
if (!token) {
toast.error('로그인이 필요합니다.');
navigate(PATH.LOGIN);
return;
}
if (!receiverRef.current || receiverRef.current.length === 0) {
toast.error('받는 사람 정보를 입력해주세요.');
return;
}
const { textMessage, senderName, messageCardId } = data;
const orderData: OrderRequest = {
productId: product.id,
message: textMessage,
messageCardId: String(messageCardId),
ordererName: senderName,
receivers: receiverRef.current.map(({ name, phone, count }) => ({
name,
phoneNumber: phone,
quantity: Number(count),
})),
};
await mutation.mutateAsync(orderData);
};
}
mutationFn: (orderData: OrderRequest) => order(orderData),
- 함수형으로 만든 이유는 순차적으로 나와야 하기 때문이다. orderData가 생성되어야 하기 때문에 함수형으로 만들었다.
onSuccess: (_, variables) => {
- variables는 성공한 것이 아닌 만든 것들을 모두 참조한다. 앞의 _는 성공한 것을 주는데 여기서는 필요 없으므로 _로 둔다.
await mutation.mutateAsync(orderData);
- return문이 async이기 때문에 await와 mutateAsync로 둔다.
- 이 함수가 async 함수이므로
- 주문 요청이 완료될 때까지 기다렸다가, 에러가 발생하면 try/catch 블록에서 잡아내거나 다음 작업을 진행할 수 있게 하기 위해서
- 예를 들어, 주문 성공 후 다음 작업이 있을 때 (여기선 onSuccess 콜백도 있지만) 좀 더 명확하게 비동기 흐름을 제어하려고
- mutate
- 콜백 함수 방식
- 성공/실패 콜백을 onSuccess, onError 옵션에서 처리
- 호출 직후 바로 리턴 (비동기 처리 완료 여부를 알 수 없음)
- mutateAsync
- Promise 반환
- await로 호출 가능해서 try/catch 구문으로 에러 처리가 가능
- 함수가 끝날 때까지 기다릴 수 있어서, 그 이후 로직을 쉽게 순차 처리 가능
'카테캠 > 2단계' 카테고리의 다른 글
| [7/22] useMutation으로 바꾸기 (3) | 2025.08.06 |
|---|---|
| [7/23] Suspense & ErrorBoundary (3) | 2025.07.23 |
| [7/22] React Query - queryClient (0) | 2025.07.22 |
| [7/22] React Query - useMutation (1) | 2025.07.22 |
| [7/22] React Query - useQuery (0) | 2025.07.22 |