본문 바로가기

programming

react-hook-form 과 meterial-UI 함께 쓰기 (3) - DateRangePicker

(1) TextField

https://tacit.tistory.com/41

 

react-hook-form 과 meterial-UI 함께 쓰기 (1) - TextField

react-hook-form은 material-UI 나 ant-D같은 외부 UI 라이브러리와 함께 사용할 수 있다. 그 중 가장 기본이 되는 TextField와 연결하는 방법을 정리해보려한다. import TextField from '@material-ui/core/TextF..

tacit.tistory.com

(2) ToggleButton

https://tacit.tistory.com/42

 

react-hook-form 과 meterial-UI 함께 쓰기 (2) - ToggleButton

이전 게시물(1) - TextField 에 이어서 이번엔 ToggleButton 과 함께 사용하는 방법에 대해 정리해보려한다. CheckBox로 예시들이 몇개 구글에 나와있다. ToggleButton도 비슷한 맥락이다. import ToggleButton fr..

tacit.tistory.com

 

 

이어서 2개의 datePicker를 조합하여 만든 dateRangePicker 를 react-hook-form 과 연결하는 방법에 대해서 정리해보려 한다.

 

우선 구현하고자 하는 것은 다음과 같다.

기간을 입력받은 range Picker  이다.

 

서버로 보내야하는 데이터는 다음과 같이 시작일 / 종료일을 보내는 것이다.

formData : {
'startDatetime' : 2022-01-30
'endDatetime' : 2022-01-30
}

 

우선 이 DateRangePicker 는 재사용할 것이므로 js파일로 따로 만들어져 있고, 부모 컴포넌트에서 import 받아서 사용한다.

 

1. 부모 컴포넌트

 

import DateRangePickerCustom from './DateRangePickerCustom';
import { useForm } from 'react-hook-form';

export default function App() {
  const { handleSubmit, control, watch, formState: {errors} } = useForm();

  const initialDate = {
    startDate : new Date(),
    endDate : new Date()
  }
  
  const onSubmit = (data) => {
    console.log(data);
  };

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <div className="modal-title">진행기간</div>
      <DateRangePickerCustom
        initialDate={initialDate}
        control={control}
        watch={watch}
      />
      <button type="submit">전송</button>
    </form>
  );
}

 

상단의 DateRangePickerCustom 으로 컴포넌트를 받아와서 사용한다.

 

이전의 TextField / ToggleButton 과는 확연히 다른 포맷이다.

1. 가장먼저 눈에 띄는 것은 UI 컴포넌트를 감싸서 사용하던 <Controller> 가 사라졌다!

2. initialDate 를 지정하여 <DateRangePickerCustom>으로 전달한다.

3. control 을 props 로 전달한다.

4. 처음 보는 watch 라는 것을 useForm에서 추가로 선언하고, props 로 전달한다.

 

그럼 이 차이점들에 대해서 하나씩 살펴보자.

 

먼저 DateRangePickerCustom.js 파일의 코드를 보면

(react-datepicker 라이브러리를 사용하엿다. https://www.npmjs.com/package/react-datepicker)

 

react-datepicker

A simple and reusable datepicker component for React

www.npmjs.com

 

import React from "react";
import DatePicker from "react-datepicker";
import "react-datepicker/dist/react-datepicker.css"
import { ko } from 'date-fns/esm/locale';
import { Controller } from 'react-hook-form';

function DateRangePickerCustom({initialDate, control, watch}) {
  console.log("control", control)
  console.log('watch', watch("startDatetime"))
 
    return (
      <>
      <div className="date-picker-wrapper">
        <Controller
          control={control}
          name="startDatetime"
          defaultValue={initialDate.startDate}
          render={({ field }) => (
            <DatePicker
              className="date-picker"
              selected={field.value}
              onChange={(date) => {
                field.onChange(date)
                console.log('field.startDatetime', field)
              }}
              selectsStart
              startDate={watch("startDatetime")}
              endDate={watch("endDatetime")}
              locale={ko}
              dateFormat="yyyy년 MM월 dd일"
            />
          )}
        />
        <div className="date-span">-</div>
        <Controller
          control={control}
          name="endDatetime"
          defaultValue={initialDate.endDate}
          render={({field}) => (
            <DatePicker
              className="date-picker"
              selected={field.value}
              onChange={(date) => {
                field.onChange(date)} 
              }
              selectsEnd
              startDate={watch("startDatetime")}
              endDate={watch("endDatetime")}
              minDate={watch("startDatetime")}
              locale={ko}
              dateFormat="yyyy년 MM월 dd일"
            />
          )}
        />
      </div>
      </>
    );
  };


  export default DateRangePickerCustom;

 

 

부모 컴포넌트에서 전달받은 initialDate, control, watch 를 받고있다.

 

1. Controller 는 name을 갖게될 하나하나의 필드값에 적용해야한다. 그러므로 부모컴포넌트에서가 아닌 자식 컴포넌트에 지정을 해야한다.

부모 컴포넌트에서는 react-hook-form과 mui를 연결해줄 control 값만 받아오고, Controller는 자식컴포넌트에서 import 하여 startDate를 위해 감싸주고, endDate를 위해 감싸주는 것처럼 각각의 필드값을 각각 감싸주는 것이다.

 

2. initialDate는 defaultValue를 지정하기 위해서 부모 컴포넌트에서 받아주었다. 

이는 다른 부모 컴포넌트들에서는 다른 initialDate를 사용하기 때문에 자식 컴포넌트에 직접 defaultValue에 적지 않았다. 무조건 new Date() 라는 값을 defaultValue 로 사용할 거라면 initialDate를 전달받지 말고 자식 컴포넌트에 바로 적어주어도 된다.

 

3. 부모로 부터 전달받은 control을 console.log로 찍어봤다.

그냥 react-hook-form 과 연결하기 위한 여러가지 값들이라고 생각하고 넘어가자...ㅎ

 

4. 이제 watch 에 대해서 알아보자.

watch는 react-hook-form 에서 제공한다.

말그대로 해당 필드의 값을 계속 지켜보겠다는 것 이다.

watch("startDatetime") 을 console.log로 찍어보았다.

시작일 값이 변경될 때마다 변경된 Date 값을 찍어준다.

 

우리의 dateRangePicker 는 시작일과, 종료일이 서로 연관되어있다. 기간의 개념으로, 종료일은 시작일보다 빠를 수 없다.

이에 대한 설정 값이 

시작일 의 경우

종료일의 경우 

여기서 기간에 대한 개념을 구현하기 위해서는 서로 다른 필드값 (startDatetime / endDatetime) 을 참조해야하는 것이다.

 

그러므로 서로 다른 필드값을 참조할 수 있든 watch를 사용한 것이다.