const {
register,
formState: { errors },
handleSubmit,
setValue,
getValues,
} = useForm({
mode: "onBlur",
});
const onSubmit = async (e: any) => {
// submit 로직
{...}
return (
<ModalContainer handleModalClose={handleModalClose}>
<CommonModalLayout title={type || "할 일 생성"}>
<form className={styles.contents} onSubmit={handleSubmit(onSubmit)}>
<UserInput
label="담당자"
placeholder="이름을 입력해 주세요"
validation={managerValidation}
setValue={setValue}
errors={errors}
value={cardData?.assignee.nickname}
/>
<CommonInput
label="제목"
name="title"
placeholder="제목을 입력해 주세요"
validation={titleValidation}
errors={errors}
required={true}
/>
{ ... }
<DateInput
label="마감일"
placeholder="날짜를 입력해 주세요"
setValue={setValue}
value={cardData?.dueDate}
/>
{ ... }
<div className={styles.modal_buttons}>
<Button.ModalColor type="submit">
{type ? "수정" : "생성"}
</Button.ModalColor>
<Button.ModalCancel type="button" onClick={handleModalClose}>
취소
</Button.ModalCancel>
</div>
</form>
</CommonModalLayout>
</ModalContainer>
);
}
function DateInput({ label, inputOnChange, placeholder }: CommonInputType) {
const [startDate, setStartDate] = useState("");
const filterPassedTime = (time: any) => {
const currentDate = new Date();
const selectedDate = new Date(time);
return currentDate.getTime() < selectedDate.getTime();
};
const onChange = (date: Date | null) => {
const formattedDate = format(date || new Date(), "yyyy-MM-dd HH:mm");
setStartDate(formattedDate);
};
return (
<div className={styles.content}>
<label htmlFor="name" className={styles.content_label}>
{label}
</label>
<div className={styles.content_date}>
<img src="/Icons/calendar.svg" alt="date" />
<DatePicker
id={label}
placeholderText={placeholder}
className={styles.content_date_input}
selected={startDate ? new Date(startDate) : new Date()}
onChange={(date) => onChange(date)}
showTimeSelect
filterTime={filterPassedTime}
dateFormat="Pp"
/>
</div>
</div>
);
}
export default DateInput;
할 일 생성시 여러 정보를 input으로 입력을 해줘야한다. 그래서 폼 태그안에 여러 input 컴포넌트를 자식요소로 넣어 사용자에게 정보를 입력받으려고 했습니다.
보다 쉽게 폼을 관리하고 유효성 검사를 수행할 수 있도록 React Hook Form을 연결해놓은 상태입니다.
마감일 정보는 react-datepicker 라이브러리를 이용해 사용자가 원하는 날짜 정보를 선택할 수 있게 하였습니다.
여기서 문제는 사용자에게 받은 마감일 정보를 React Hook Form과 연결을 해줘야하는데 input 요소가 아닌 것과 연결이 가능한가? 라는 생각이 들어 열심히 방법을 찾아보았습니다.
const {
register,
formState: { errors },
handleSubmit,
setValue,
getValues,
control, // 컨트롤러 추가
} = useForm({
mode: "onBlur",
});
const onSubmit = async (e: any) => {
// submit 로직
{...}
return (
<ModalContainer handleModalClose={handleModalClose}>
<CommonModalLayout title={type || "할 일 생성"}>
<form className={styles.contents} onSubmit={handleSubmit(onSubmit)}>
{ ... }
<DateInput
label="마감일"
placeholder="날짜를 입력해 주세요"
control={control} // 컨트롤러 추가
setValue={setValue}
value={cardData?.dueDate}
/>
{ ... }
<div className={styles.modal_buttons}>
<Button.ModalColor type="submit">
{type ? "수정" : "생성"}
</Button.ModalColor>
<Button.ModalCancel type="button" onClick={handleModalClose}>
취소
</Button.ModalCancel>
</div>
</form>
</CommonModalLayout>
</ModalContainer>
);
}
import { Controller } from "react-hook-form";
function DateInput({ label, control, setValue, value }: DateInputType) {
const filterPassedTime = (time: any) => {
const currentDate = new Date();
const selectedDate = new Date(time);
return currentDate.getTime() < selectedDate.getTime();
};
const defaultDate = new Date();
return (
<div className={styles.content}>
<label htmlFor="name" className={styles.content_label}>
{label}
</label>
<div className={styles.content_date}>
<img src="/Icons/calendar.svg" alt="date" />
<Controller
name="dueDate"
defaultValue={value || format(defaultDate, "yyyy-MM-dd HH:mm")}
control={control}
render={({ field: { onChange, onBlur, value, ref } }) => (
<DatePicker
ref={ref}
placeholderText="날짜를 입력해 주세요"
className={styles.content_date_input}
selected={value ? new Date(value) : new Date()}
dateFormat="yyyy-MM-dd HH:mm"
showTimeSelect
onChange={(date: Date) => {
const formattedDate = format(
date || new Date(),
"yyyy-MM-dd HH:mm"
);
setValue("dueDate", formattedDate);
}}
onBlur={onBlur}
filterTime={filterPassedTime}
/>
)}
/>
</div>
</div>
);
}
export default DateInput;
찾아보니 React Hook Form 이용해 라이브러리나 input태그가 아닌 요소 즉 비제어 컴포넌트의 값을 폼 데이터로 감싸주게 하려면 Controller를 이용해야한다는 걸 알게 되었습니다.
Controller의 name 속성은 이 필드가 폼 데이터에서 어떤 키로 저장될지를 지정합니다.
defaultValue 속성은 입력 필드의 초기 값을 설정합니다.
control 속성은 React Hook Form에서 폼 상태를 관리하는 객체입니다. Prop으로 control을 연결해 Controller가 폼과 상호작용할 수 있습니다.
render prop은 Controller가 자식으로 렌더링할 컴포넌트를 정의합니다. 이 경우, DatePicker 컴포넌트를 렌더링합니다.
완성된 코드로 테스트를 해보니 폼 데이터 잘 묶어서 전달이 되는 걸 확인 할 수 있습니다.