Open1
typescriptで<input type="date" />を使う際のstate型について

困りごと
- valueは以下のように常にyyyy-mm-ddの文字列型で指定する必要がある
<input type="date" value="2017-06-01" />
- ただ、date型が日付を管理する上では使いやすい
- また、次点でnumber型で管理する方が大小比較や値の書き換えの観点で使い回しやすかったり、dateとの変換がしやすかったりして便利
- 具体的にはstringだと…
// stateの定義とinputタグ自体はシンプルに書けるけど...
const [stringDate, setStringDate] = useState('');
<input
value={stringDate}
onChange={(e) => setStringDate(e.target.value)}
/>
// date -> string
stringDate = dateDate.toISOString().slice(0,10)
// これで"2023-04-17T01:52:26.878Z"の"2023-04-17"だけを取得できる
// とはいえ可読性も低いし、毎回書くのは結構めんどくさい
// string -> date
dateDate = new Date(Date.parse(stringDate))
- numberだと
// date -> number
numberDate = dateDate.getTime()
// number -> date
dateDate = new Date(numberDate)
- なのでできるだけnumber型やdate型でstateは管理したい
解決策
- number型の場合
const [numberDate, setNumberDate] = useState(0);
// stringとの変換が面倒なので関数化
const stringToNumber = (stringD: string) => {
const _dateDate = new Date(Date.parse(stringD));
return _dateDate.getTime();
};
const numberToString = (numberD: number) => {
const _dateDate = new Date(numberD);
return _dateDate.toISOString().slice(0, 10);
};
<input
type="date"
value={numberToString(numberDate)}
onChange={(e) => setNumberDate(stringToNumber(e.target.value))}
/>
- date型の場合
const [dateDate, setDateDate] = useState(new Date());
<input
type="date"
value={dateDate.toISOString().slice(0, 10)}
onChange={(e) => setDateDate(new Date(Date.parse(e.target.value)))}
/>
まとめ
どの型でstate管理するかだが
- string型
- 大小比較、必要なデータの取り出しやデータの書き換えがめんどくさい観点で避けたい
- number型
- 大小比較はできるものの必要なデータの取り出しやデータの書き換えは面倒
- string型との書き換えがめんどくさい
- date型
- .getTime()メソッドを使っての大小比較、get…()メソッドを使っての必要なデータの取り出し、set…()メソッドを使ってのデータの書き換えがしやすい
- stringとの書き換えはdate→stringは若干トリッキーだが、inputタグのみで使用することを考えると記述箇所は限定的
より、date型で管理するのが良いのではないかなあと思っている
参考リンク
codesandbox: https://codesandbox.io/s/react-input-type-date-test-rr5vr7?file=/src/App.tsx:1407-1570
mdn docs: https://developer.mozilla.org/ja/docs/Web/HTML/Element/input/date