課題
Reactでフォームを実装したい。
React Hooksでcountを管理している。
ここで、素直にinputに値を渡して、変更があればinputの返り値で価格を変更してみる。
index.tsx
import { useState } from 'react'
const Index = () => {
const [count, setCount] = useState(0)
return <input
type='number'
value={count}
onChange={e=>setCount(e.target.value)}
/>
}
export default Index
今回は、初期値0から100に変更したとする
初期値は、number型の0
変更があると、string型の100となる。
これでは困る。
別のcount=500
があったとしてその合計を求めると、'100500'
となってしまう。
解決法
React hooksやreduxなどデータストアの型は変えない。
→表示するときに適した型に変換する
→変更があるときは、データストアと同じ型に変換する
の2つを守れば大体解決する
index.tsx
import { useState } from 'react'
const Index = () => {
const [price, setPrice] = useState(0)
return <input
type='number'
value={price==0 ? '' : String(price)}
onChange={e=>setPrice(Number(e.target.value))}
/>
}
export default Index
// or
import { useState } from 'react'
const Index = () => {
const [price, setPrice] = useState(0)
return <input
type='number'
value={isNaN(price) ? '' : String(price)}
onChange={e=>setPrice(e.target.valueAsNumber)}
/>
}
export default Index
このようにこのように型を合わせてあげれば良い。
少し余計な処理があるが、これはinputを全部消してもデータストアは0にしかならず、0が必ず最後に表示されてしまうため0を消す処理を書いている。
個人的に、NaNを用いた方が見やすいと考えている。
データを送信するときに、入力のバリデーションでcount==0
とisNaN(count)
だと後者の方が0を許容できるのと直感的だから。