React

react-datepickerを使ってsessionStorageに保存した値が取得できない時の解決策

先日Next.jsでWebサービスを開発したのですが、日付入力をする項目があったので、react-datepickerでカレンダーを実装しました。

そのサービスは入力値をsessionStorageに保存する仕様で、もれなく入力した日付も保存します。

保存はうまくいったのですが、保存したデータを取得すると、日付が無効な値であると怒られてしまいました。

事象

実現したかったこと

react-datepickerを使ってsessionStorage(またはlocalStorage)に日付を保存し、ページをロードした際に、保存したデータが反映されるようにしたかったのです。

エラー内容

sessionStorageへの保存は問題なくできたのですが、データの取得でこのようなエラーが表示されました。

どうやら有効な時間の値として認識されていないようです。

Unhandled Runtime Error
RangeError: Invalid time value

エラー発生時の対象ソースコード

react-datepickerのstateはDate型で管理する必要があるため、useStateでDate型のstate変数をcreateStateとして宣言しています。

以下はエラーが発生したときのコードです。

const CreateDatePage = () => {
  // state変数と関数
  const [createDate, setCreateDate] = useState<Date>(new Date());

  // Get Data
  useEffect(() => {
    if (sessionStorage.getItem(RESUME_DATA) !== null) {
      const data: ResumeProps = JSON.parse(sessionStorage.getItem(RESUME_DATA) as string);

      setCreateDate(date);
    }
  }, []);

  // Save Data
  useEffect(() => {
    const timer = setTimeout(() => {
      if (sessionStorage.getItem(RESUME_DATA) !== null) {
        const data: ResumeProps = JSON.parse(sessionStorage.getItem(RESUME_DATA) as string);

        data.createDate = createDate;

        sessionStorage.setItem(RESUME_DATA, JSON.stringify(data));
      }
    }, 500);
    return () => {
      clearTimeout(timer);
    };
  }, [createDate]);

  return (
    <Layout title="作成日">
      <DatePicker
        dateFormat="yyyy/M/d"
        locale="ja"
        selected={createDate}
        onChange={(date: Date) => setCreateDate(date)}
        className="block bg-white border border-gray rounded py-2 px-2 focus:outline-none"
      />
    </Layout>
  );
};

export default CreateDatePage;

解決策

取得した値はstring型で返ってくるため、Date型に変換する必要がある!

sessionStorageでデータの保存(setItem)や取得(getItem)をする際は、データのやり取りを文字列で行います。

データを取得する際は文字列になっているデータをJSON.parse()でJSONデータに変換し、取得した値をstate関数に設定します。

今回の場合、取得した日付データはstring型として返却されるので以下のコードのようにstate関数に値を設定する前にDate型に変換する必要があるのです。

// Get Data
  useEffect(() => {
    if (sessionStorage.getItem(RESUME_DATA) !== null) {
      const data: ResumeProps = JSON.parse(sessionStorage.getItem(RESUME_DATA) as string);

      // string型として返ってきた値をDate型に変換し、その値を格納した変数
      const date = typeof data.createDate === 'string' ? new Date(data.createDate) : data.createDate;
      // 上記の変数を設定する
      setCreateDate(date);
    }
  }, []);

おわりに

sesstionStorageやlocalStorageでデータの保存や取得をする際は、データのやり取りを文字列で行わなければなりません。

このことをきちんと理解していればなんてことないエラーでしたが、随分と時間を費やしてしまいました😅