onSubmit로 폼 제출시 유효성 검사하기
요구사항에 따르면 MessageForm과 CashReceiptForm 값에 대한 유효성을 한번에 검사해야 한다.
이전에 구현한 내 코드를 보자.
가장 상위의 orderPage에서 여러 하위 컴포넌트들을 하나의 폼 태그로 감싸주고 있다.
<form>
<FormWrapper>
<Container maxWidth="1280px" justifyContent="flex-start" alignItems="flex-start">
<InnerContainer>
<OrderMainSection product={productData.product} />
<OrderAsideSection
productId={productData.product.detail.id}
totalCost={getTotalCost()}
/>
</InnerContainer>
</Container>
</FormWrapper>
</form>
폴더구조를 살펴보면 OrderMainSection 하위에 메세지 폼이, OrderAsideSection 하위에 현금영수증 폼이 있는 구조이다.
📦Order
┣ 📂OrderAsideSection
┃ ┣ 📜component.tsx
┃ ┗ 📜index.tsx
┗ 📂OrderMainSection
┃ ┣ 📂MessageFormSection
┃ ┃ ┗ 📜index.tsx
┃ ┣ 📜component.tsx
┃ ┗ 📜index.tsx
깔끔한 코드를 위한 선택이였다만… 이렇게 되면 OrderPage에서 한번에 유효성 검사를 하려고 했을 때 엄청난 Props drilling이 일어나게 된다…. 계속 넘겨주고 넘겨받고 악순환의 반복이였다. 그나마 찾아낸 해결책이 Context를 사용하는 방법인데, 코드가 너무 장황해져서 다른 방법을 찾아보기 시작했다.
직관적인게 최고다.
전체적인 구조를 바꾸기로 했다. 초반에 조금만 고생하고 생각해둔 로직만 덧붙이면 요구사항들을 금방 구현할 수 있을 것 같았다.
우선 form과 세부적인 주문 정보들을 다른 컴포넌트로 분리했다. 이렇게 되면 OrderPage에서 한 단계만 거치면 바로 폼에 접근할 수 있다.
<form onSubmit={handleSubmit}>
{...}
<MessageFormSection
onMessageChange={(message) => setFormData({ ...formData, message })}
/>
<OrderMainSection product={productData.product} />
</div>
<div>
<h6 className="order-aside-title">
<span className="span-title">결제 정보</span>
</h6>
<Divider aria-orientation="horizontal" />
<CashReceiptForm
onReceiptDataChange={(cashReceiptData) =>
setFormData({ ...formData, cashReceiptData })
}
/>
<OrderAsideSection totalCost={getTotalCost()} />
</div>
{...}
</form>
그리고 각 폼에서 유효성을 검사하고, 에러 메세지를 반환하는 함수를 작성했다.
export const validateMessageForm = (message: string) => {
let messageError = '';
if (message.trim().length === 0) messageError = '메세지를 입력해주세요.';
if (message.trim().length > 100) messageError = '메세지는 100자 이내로 입력해주세요.';
return messageError;
};
formData 사용하기
formData에 message와 cashReceiptData 필드를 생성했다.
const [formData, setFormData] = useState<FormData>({
message: '',
cashReceiptData: { isReceiptChecked: false, receiptNumber: '' },
});
이렇게 되면 formData의 각 필드에 담긴 값을 작성해둔 validate 함수로 간편하게 유효성 검사를 할 수 있고, 결과에 따라 적절한 메세지를 사용자에게 보여줄 수 있다.
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
const messageError = validateMessageForm(formData.message);
const receiptError = validateReceiptForm(formData.cashReceiptData);
if (messageError) {
alert(`${messageError}`);
return;
}
if (receiptError) {
alert(`${receiptError}`);
return;
}
{..후략}
최종 폴더 구조
📦Order
┣ 📂Form
┃ ┣ 📂CashReceiptFormSection
┃ ┃ ┗ 📜index.tsx
┃ ┗ 📂MessageFormSection
┃ ┃ ┗ 📜index.tsx
┣ 📂OrderAsideSection
┃ ┣ 📜component.tsx
┃ ┗ 📜index.tsx
┣ 📂OrderMainSection
┃ ┣ 📜component.tsx
┃ ┗ 📜index.tsx
┗ 📂util
┃ ┗ 📜storage.ts
'FE > React & TS' 카테고리의 다른 글
[react-Query] useMutation 사용해서 데이터 변경과 예외처리 하기 (0) | 2024.08.02 |
---|---|
[TS] useQuery 커스텀 훅 사용하기 (0) | 2024.07.21 |
[TS] useInfiniteQuery와 useInView 훅으로 무한스크롤 구현하기 (0) | 2024.07.14 |
[TS] React Query와 Suspense, ErrorBoundary 함께 사용하기 (0) | 2024.07.14 |
프론트엔드에서 효과적으로 비동기 처리하기(feat. TanStack Query & Suspense) (0) | 2024.07.13 |