-
Notifications
You must be signed in to change notification settings - Fork 1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Feat/#238] HostApplyPage 폼 react-hook-form 도입 #240
base: develop
Are you sure you want to change the base?
Changes from 3 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10,18 +10,27 @@ import { | |
titleStyle, | ||
} from './StepOne.style'; | ||
import { smoothScroll } from '@utils'; | ||
import { useHostApplyInputChange, useHostApplyInputValidation } from '@pages/host/hooks'; | ||
import { useAtom } from 'jotai'; | ||
import { hostApplyAtom } from '@stores'; | ||
import { Controller, useForm } from 'react-hook-form'; | ||
import { components } from '@schema'; | ||
|
||
const StepOne = ({ onNext }: StepProps) => { | ||
const { hostApplyState, handleInputChange } = useHostApplyInputChange(); | ||
const { validateStepOne } = useHostApplyInputValidation(); | ||
const { isIntroValid, isGoalValid, isLinkValid, isAllValid } = validateStepOne(hostApplyState); | ||
const [hostApplyState, setHostApplyState] = useAtom(hostApplyAtom); | ||
|
||
const handleNextClick = () => { | ||
if (isAllValid) { | ||
onNext(); | ||
smoothScroll(0); | ||
} | ||
const { | ||
control, | ||
handleSubmit, | ||
formState: { errors, isSubmitting }, | ||
} = useForm({ | ||
defaultValues: hostApplyState, | ||
mode: 'onBlur', | ||
}); | ||
|
||
const onSubmit = (data: components['schemas']['SubmitterCreateRequest']) => { | ||
setHostApplyState((prev) => ({ ...prev, ...data })); | ||
onNext(); | ||
smoothScroll(0); | ||
}; | ||
|
||
return ( | ||
|
@@ -32,50 +41,79 @@ const StepOne = ({ onNext }: StepProps) => { | |
<h4 css={titleStyle}>호스트 신청</h4> | ||
<h1 css={subTitleStyle}>호스트님에 대해 알려주세요!</h1> | ||
</header> | ||
<main css={mainStyle}> | ||
<section css={sectionStyle}> | ||
<QuestionText numberLabel="Q1">호스트님은 어떤 분이신가요?</QuestionText> | ||
<TextArea | ||
size="medium" | ||
maxLength={300} | ||
placeholder={`호스트님에 대해 자유롭게 소개해 주세요! \n모임 참여 및 개최 경험 등도 좋아요.`} | ||
value={hostApplyState.intro} | ||
onChange={(e) => handleInputChange(e, 'intro')} | ||
isValid={isIntroValid} | ||
errorMessage="빈칸을 입력해주세요." | ||
/> | ||
</section> | ||
<section css={sectionStyle}> | ||
<QuestionText numberLabel="Q2">호스트로 이루고 싶은 목표를 알려주세요!</QuestionText> | ||
<TextArea | ||
size="medium" | ||
maxLength={300} | ||
placeholder={`모임에서 어떤 가치를 공유하고 싶으신가요? \n그 이유는 무엇인가요?`} | ||
value={hostApplyState.goal} | ||
onChange={(e) => handleInputChange(e, 'goal')} | ||
isValid={isGoalValid} | ||
errorMessage="빈칸을 입력해주세요." | ||
/> | ||
</section> | ||
<section css={sectionStyle}> | ||
<QuestionText numberLabel="Q3"> | ||
호스트님을 잘 알 수 있는 SNS 혹은 홈페이지 링크를 첨부해 주세요! | ||
</QuestionText> | ||
<Input | ||
value={hostApplyState.link} | ||
onChange={(e) => handleInputChange(e, 'link')} | ||
placeholder="URL을 첨부해주세요." | ||
isValid={isLinkValid} | ||
errorMessage="올바른 URL 형식을 입력해주세요" | ||
isCountValue={false} | ||
/> | ||
</section> | ||
</main> | ||
<footer css={footerStyle}> | ||
<Button variant="large" onClick={handleNextClick} disabled={!isAllValid}> | ||
다음 | ||
</Button> | ||
</footer> | ||
|
||
<form onSubmit={handleSubmit(onSubmit)} > | ||
<main css={mainStyle}> | ||
<section css={sectionStyle}> | ||
<QuestionText numberLabel="Q1">호스트님은 어떤 분이신가요?</QuestionText> | ||
<Controller | ||
name="intro" | ||
control={control} | ||
rules={{ required: '빈칸을 입력해주세요.' }} | ||
render={({ field }) => ( | ||
<TextArea | ||
{...field} | ||
size="medium" | ||
maxLength={300} | ||
placeholder={`호스트님에 대해 자유롭게 소개해 주세요! \n모임 참여 및 개최 경험 등도 좋아요.`} | ||
aria-invalid={!!errors.intro} | ||
isValid={!errors.intro} | ||
errorMessage={errors.intro?.message} | ||
/> | ||
)} | ||
/> | ||
</section> | ||
<section css={sectionStyle}> | ||
<QuestionText numberLabel="Q2">호스트로 이루고 싶은 목표를 알려주세요!</QuestionText> | ||
<Controller | ||
name="goal" | ||
control={control} | ||
rules={{ required: '빈칸을 입력해주세요.' }} | ||
render={({ field }) => ( | ||
<TextArea | ||
{...field} | ||
size="medium" | ||
maxLength={300} | ||
placeholder={`모임에서 어떤 가치를 공유하고 싶으신가요? \n그 이유는 무엇인가요?`} | ||
aria-invalid={!!errors.goal} | ||
isValid={!errors.goal} | ||
errorMessage={errors.goal?.message} | ||
/> | ||
)} | ||
/> | ||
</section> | ||
<section css={sectionStyle}> | ||
<QuestionText numberLabel="Q3"> | ||
호스트님을 잘 알 수 있는 SNS 혹은 홈페이지 링크를 첨부해 주세요! | ||
</QuestionText> | ||
<Controller | ||
name="link" | ||
control={control} | ||
rules={{ | ||
required: '올바른 URL 형식을 입력해주세요.', | ||
pattern: { | ||
value: /^(https?:\/\/)?([\w-]+(\.[\w-]+)+\/?)([^\s]*)?$/i, | ||
message: '올바른 URL 형식을 입력해주세요.', | ||
}, | ||
}} | ||
render={({ field }) => ( | ||
<Input | ||
{...field} | ||
placeholder="URL을 첨부해주세요." | ||
isValid={!errors.link} | ||
errorMessage={errors.link?.message} | ||
isCountValue={false} | ||
/> | ||
)} | ||
/> | ||
Comment on lines
+89
to
+108
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 프로젝트에서 사용되고 있는 Input들이 모두 form에서 사용된다면 Controller를 Input안으로 옮겨서 Input컴포넌트 자체를 react-hook-form 을 사용하는 Input으로 만드는 것은 어떤가요? 그냥 Input도 필요하다면 Controller를 포함하는 Input을 FormInput이라고 한다던지 해서, Controller로 감싸는 부분을 공통 컴포넌트 안으로 넣어버리는게 좋지 않을까..? 라는 생각인데 어떠신가요? 저도 react-hook-form을 안써봐서 여러 의견 부탁드립니다. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 일단 그런 방식도 생각을 해봤는데 안해봐서 되는지는 확인을 해봐야 할 것 같습니다. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 제가 찾아봤을 때는 (레퍼는 기억이 안나서,, 찾으면 댓글로 추가하겠습니다 ㅠ) 그렇게 컴포넌트 안에 Controller를 함께 포함하는 것이 가능할 뿐 아니라, 일반적으로 이렇게 많이 사용하는 것 같았습니다. 제 생각에도 Input 컴포넌트 자체를 수정하는 것은 좀 아닌것 같고, Input컴포넌트를 Controller로 감싸놓은 FormInput이라는 새로운 컴포넌트를 만드는게 어떨까라고 생각합니다. |
||
</section> | ||
</main> | ||
<footer css={footerStyle}> | ||
<Button variant="large" type="submit" disabled={isSubmitting}> | ||
다음 | ||
</Button> | ||
</footer> | ||
</form> | ||
</div> | ||
</> | ||
); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
undefined를 옵셔널로 주신 이유가 있으실까요?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
이부분에 undefined을 주지 않으면 CategorySelectBox 컴포넌트를 호출하는 부분에서 selectedCategories을 prop으로 넘겨줄 때 category1만 string값이 부여되어 있고, category2,3은 string | undefined 타입이라 타입에러가 떠서 이런식으로 수정했습니다!