util - once 함수 사용하기 (feat. error in typescript)

LNSol·2023년 3월 19일

React

목록 보기
9/10

최근에 정기구독 서비스를 만들어 배포했다. 신청할 서비스, 주기와 요일을 선택하면 따로 신청하지 않아도 정기적으로 서비스를 이용할 수 있다. 서비스에 대한 결제는 해당 정기구독의 마지막 서비스가 완료되면 자동으로 결제된다. 다음 화면은 청소 서비스를 진행해주시는 매니저님 분들이 사용하는 앱이다.

서비스 종료 촬영까지 마친 후 끝! → 알림 보내기까지 완료되면 서비스가 완료된다.

아래 사진에서 보낼게요! 버튼을 클릭하면 서버로 자동 결제 요청을 보내는데 저 버튼을 빠르게 연속해서 누르면 결제 또한 여러 번 이루어졌다… 중복 결제를 방지하고자 once라는 유틸 함수를 만들어 적용해보았다.

utils/utils.ts

export const once = (fn: Function) => {
	let isDone = false;
	
	return (...args: any[]) => {
		if (!isDone) {
			isDone = true;
			fn(...args);
		}
	};
};

타입스크립트에서 any 타입은 최대한 사용하지 않는 것이 좋지만 어느 곳에서 어떻게 사용될 지 모르는 util 함수이기에 어쩔 수 없이 사용했다..
우선 보낼게요! 버튼 클릭시 호출되는 함수는 다음과 같았다.

const checkDoneEnd = () => {
	// console.log('checkDoneEnd!!');
	onchangestate(5);
	setOpenEnd(false);
};

현재 서비스의 진행 상태를 나타내는 값을 변경해주고 모달을 닫아주는게 끝이다. state가 5로 변경되면 서비스가 완료된 것이며, 각 서비스들의 상태를 done으로 변경 후 서버와 고객앱으로 sync emit을 보내고 고객에게 서비스 종료 알림을 보낸다.

정기구독 자동 결제 요청을 보내는 함수 completeService()를 만들과 다음과 같이 수정했다.

// 정기구독 서비스 자동결제 요청 함수
const completeService = async () => {
	const { bsids, visitdt, custaddr } = billservices;
	try {
		const result = await Store.sendPost(`${SERVER_PAGE}/standingpay`, {
			billServiceIds: bsids?.split(',').map((id) => NUmber(id) || [],
			visitdt,
			custaddr,
		});

		if (result) 
			addChatMsg(6, billservice.custid);
	
		onchangestate(5);
	} catch (error) {
		console.error(error);
		const { message } = error as unknown as AxiosError; // ***
		setErrorMessage(message);
		setErrorStanding(true);
	}
};

// 서비스 끝 (문닫힘) + 정기구독 서비스 자동결제
const checkDoneEnd = useCallback(
	once(() => {
		// onchangestate(5);
		setOpenEnd(false);
		completeService();
	}),
	[setOpenEnd, completeService]
);

useCallback과 once 함수를 같이 사용하여 ‘보낼게요!’버튼을 빠르게 연속 클릭하여도 결제 요청은 단 한 번만 보내도록 수정했다.

사실 여기서 더 중요한 것은 *** 표시가 있는 부분이다. 혹시 결제 진행이 정상적으로 이루어지지 않은 경우 매니저님분들이 확인하고 사무실로 연락을 줄 수 있도록 메시지를 띄워줘야 하는데 타입 에러가 나서 어서션을 통해 타입을 좁히는 방법을 선택했었다.

동료 개발자님과 cto 본부장님과 타입스크립트 스터디를 계획중인데 시작 전에 책 한권을 1독하면서 알게된 내용은 일단 저 방법은 절대 권장하지 않는 방법이었다.

우선 에러의 원인은 에러의 타입은 실제로 알 수 없기 때문에 any 혹은 unknown이다. 왜나면 throw로 에러를 던질 때 에러 객체 뿐만 아니라 다른 어떤 값도 던질 수 있기 때문이다.

throw 'Error';

마침 해당 내용을 다루는 챕터의 발표자가 나여서 발표와 동시에 이 코드를 보고 수정하고 새로 업로드를 할 계획이다.

0개의 댓글