React セット値が画面に反映されない問題

## 事象
[こちらのフォーム画面](https://qiita.com/buto/items/f3991f0a86f2bef0f3f3)でいうと変更画面、初期表示時にAPIから取得した値を書く入力項目にセットする時に一部の項目がundefinedになってしまい値がセットされないことがあった

開始〜終了がセットされていません。。
![スクリーンショット 2022-12-06 21.45.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/530205/57390560-a3b9-950d-acb3-7bf1c4083373.png)


## ここがダメだったぽい
再現した条件はこちら
1. react-datepickerを利用した独立DatePickerコンポーネント（フォーム画面本体からインポートされる）
1. DatePickerコンポーネントは引数にstring日付をもらい、string⇆Date変換をしている

この条件でフォーム画面に初期値をセットしている `useEffect` 第2引数を空配列にしていたのが悪さしていた様子。。


```tsx
import React, { useEffect, useState } from "react";
import DatePicker from "react-datepicker";
import "react-datepicker/dist/react-datepicker.css"

interface Props {
    date: string
    onChange: (date: string) => void
}

const DatePickerComponent = ({date = "", onChange}: Props) => {
    const [selectedDate, setSelectedDate] = useState<Date>();

    // 不具合の原因
    useEffect(() => {
        if (date !== "") {
            setSelectedDate(stringToDate(date));
        }
    }, [])

    /**
     * string日付をDate型に変換する
     * @param strDate 
     * @returns 
     */
    const stringToDate = (strDate: string) => {
        return new Date(strDate);
    }

    /**
     * Date型をstring日付に変換する
     * @param date 
     * @returns 
     */
    const dateToString = (date: Date) => {
        const ymd = `${date.getFullYear()}/${date.getMonth() + 1}/${date.getDay()}`;
        const hm = ("0" + date.getHours()).slice(-2) + ":" + ("0" + date.getMinutes()).slice(-2);
        return `${ymd} ${hm}:00.000+09:00`;
    }

    return (
        <DatePicker 
            dateFormat="yyyy/MM/dd HH:mm"
            selected={selectedDate} 
            onChange={date =>{
                if (date) {
                    onChange(dateToString(date));
                }
            }}/>
    )
}
export default DatePickerComponent;
```

## こうしたら直った（旧）
原因の `useEffect` 第2引数にpropsから渡る変数 `date` を紐づけると解決した

```tsx
    // 不具合の原因
    useEffect(() => {
        if (date !== "") {
            setSelectedDate(stringToDate(date));
        }
    }, [date])
```
## useMemoを使おう

コメントいただいたように `selectedDateの値 = dateの値` なのでこういうケースでは `useMemo()` の方が効率が良いようです！！

```tsx
import React, { useMemo } from "react";
import DatePicker from "react-datepicker";
import "react-datepicker/dist/react-datepicker.css"

interface Props {
    date: string
    onChange: (date: string) => void
}

const DatePickerComponent = ({date = "", onChange}: Props) => {

    /**
     * string日付をDate型に変換する
     * @param strDate 
     * @returns 
     */
    const stringToDate = (strDate: string) => {
        if (date === "") return; 
        return new Date(strDate);
    }

    /**
     * Date型をstring日付に変換する
     * @param date 
     * @returns 
     */
    const dateToString = (date: Date) => {
        const ymd = `${date.getFullYear()}/${date.getMonth() + 1}/${date.getDay()}`;
        const hm = ("0" + date.getHours()).slice(-2) + ":" + ("0" + date.getMinutes()).slice(-2);
        return `${ymd} ${hm}:00.000+09:00`;
    }

    const selectedDate = useMemo(() => stringToDate(date), [date]);

    return (
        <DatePicker 
            dateFormat="yyyy/MM/dd HH:mm"
            selected={selectedDate} 
            onChange={date =>{
                if (date) {
                    onChange(dateToString(date));
                }
            }}/>
    )
}
export default DatePickerComponent;
```