React DatePickerのcustomInputにrefを適用する

`react-datepicker`の`customInput`に`ref`を適用する方法です。
まずはサンプルを。

```tsx
import React from "react";
import DatePicker from "react-datepicker";

interface InputProps {
  inputRef: React.Ref<HTMLInputElement>;
  onClick?: React.MouseEventHandler<HTMLInputElement>;
  onChange?: React.ChangeEventHandler<HTMLInputElement>;
  value?: string | ReadonlyArray<string> | number;
}

const Input = React.forwardRef<HTMLInputElement, InputProps>((props, ref) => {
  return <input
    type="text"
    ref={props.inputRef}
    onClick={props.onClick}
    onChange={props.onChange}
    value={props.value}
  />;
})

interface Props {
  inputRef: React.Ref<HTMLInputElement>;
}

const DP: React.FC<Props> = props => {
  const [selected, setSelected] = React.useState<Date | null>(null);
  const onChangeDatePicker = (date: Date | [Date, Date] | null) => {
    if (date && date instanceof Date) {
      setSelected(date);
    }
  };
  return (
    <DatePicker
      selected={selected}
      onChange={onChangeDatePicker}
      customInput={
        <Input inputRef={props.inputRef} />
      } />
  );
};

const App: React.FC = () => {
  const ref = React.useRef<HTMLInputElement>(null);
  const onClick: React.MouseEventHandler<HTMLButtonElement> = event => {
    console.log(ref.current?.value);
  };
  return (
    <form>
      <DP inputRef={ref} /><br/>
      <button type="submit" onClick={onClick}>送信</button>
    </form>
  );
};
```

順番に説明していきます。

# `customInput`に指定するコンポーネント

`DatePicker` の `customInput` に指定するコンポーネントは以下のように定義します。

```tsx
interface InputProps {
  inputRef: React.Ref<HTMLInputElement>; // ①
  onClick?: React.MouseEventHandler<HTMLInputElement>; // ②
  onChange?: React.ChangeEventHandler<HTMLInputElement>; // ②
  value?: string | ReadonlyArray<string> | number; // ②
}

const Input = React.forwardRef<HTMLInputElement, InputProps>((props, ref) => { // ③
  return <input
    type="text"
    ref={props.inputRef} // ④
    onClick={props.onClick}
    onChange={props.onChange}
    value={props.value}
  />;
})
```

## ① プロパティに`React.Ref`型の値を定義

プロパティに`React.Ref`型の値を定義します。
名称は`ref`以外にする必要があります。

## ② プロパティに`customInput`として動作するための値を定義

プロパティに`onChange``onClick``value`を定義します。
これらを定義しなければ`DatePicker`の`customInput`として正常に動作しません。

## ③ コンポーネントは`forwardRef`で定義

`ref`を親子間で受け渡せるよう`forwardRef`でコンポーネントを定義します。
ただし引数`ref`は使用しません。

## ④ `ref`を適用したいコンポーネントにプロパティを指定

`ref`を適用したいコンポーネントに`forwardRef`の引数ではなくプロパティの`React.Ref`型の値を指定します。

# `DatePicker`の定義

`customInput`に指定するコンポーネントを定義したら、これを使用して`DatePicker`を定義します。

```tsx
interface Props {
  inputRef: React.Ref<HTMLInputElement>; // ⑤
}

const DP: React.FC<Props> = props => {
  const [selected, setSelected] = React.useState<Date | null>(null);
  const onChangeDatePicker = (date: Date | [Date, Date] | null) => {
    if (date && date instanceof Date) {
      setSelected(date);
    }
  };
  return (
    <DatePicker
      selected={selected}
      onChange={onChangeDatePicker}
      customInput={
        <Input inputRef={props.inputRef} /> // ⑥
      } />
  );
};
```

## ⑤ プロパティに`React.Ref`型の値を定義

プロパティに`React.Ref`型の値を定義します。
名称は`ref`以外にしたほうが無難です。

## ⑥ `customInput`のコンポーネントにプロパティを指定

`customInput`のコンポーネントにプロパティの`React.Ref`型の値を指定します。

# `useRef`の定義

```tsx
const App: React.FC = () => {
  const ref = React.useRef<HTMLInputElement>(null); // ⑦
  const onClick: React.MouseEventHandler<HTMLButtonElement> = event => {
    console.log(ref.current?.value); // ⑧
  };
  return (
    <form>
      <DP inputRef={ref} /><br/> // ⑨
      <button type="submit" onClick={onClick}>送信</button>
    </form>
  );
};
```

## ⑦ `ref`を定義

`useRef`で`ref`を定義します。

## ⑧ `ref`の使用

イベントハンドラ等で`ref`を使用します。

## ⑨ `ref`を適用

`ref`を適用します。