Taskify 트러블 슈팅 3

윤병현·2024년 5월 21일
0

Taskify

목록 보기
7/7
post-thumbnail

🚨 이슈 발생

🔍 할 일 생성 모달 로직

  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>
  );
}

🔍 Date input 로직

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>
  );
}

🔍 개선된 Date input 로직

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를 이용해야한다는 걸 알게 되었습니다.

  1. Controller의 name 속성은 이 필드가 폼 데이터에서 어떤 키로 저장될지를 지정합니다.

  2. defaultValue 속성은 입력 필드의 초기 값을 설정합니다.

  3. control 속성은 React Hook Form에서 폼 상태를 관리하는 객체입니다. Prop으로 control을 연결해 Controller가 폼과 상호작용할 수 있습니다.

  4. render prop은 Controller가 자식으로 렌더링할 컴포넌트를 정의합니다. 이 경우, DatePicker 컴포넌트를 렌더링합니다.

완성된 코드로 테스트를 해보니 폼 데이터 잘 묶어서 전달이 되는 걸 확인 할 수 있습니다.

profile
프론드엔드 개발자

0개의 댓글

관련 채용 정보