useState 引数は primitive? object?


先日の投稿の続きです。「memoize input array を空にする」ことにこだわらなければ、この憂慮は不要です。handler関数が外側のstate を参照しない様にした場合、以下の様な課題に遭遇します。

const [flag, setFlag] = useState(true)
const [count, setCount] = useState(0)

const handleToggleFlag = useCallback(() => {
  setFlag(prev => !prev)
},[])
const handleIncrement = useCallback(() => {
  setCount(prev => {
    if (!flag) return prev
    return prev + 1
  })
},[flag]) // これを空にしたい

動くには動きますが、flag 更新毎に handleIncrement が再定義されてしまいます。解決策として state を object 一つに集約する方法があります。useState の引数は「object である必要はないが、要望があれば可能」とされています。

const [state, update] = useState({
  flag: true,
  count: 0
})
const handleToggleFlag = useCallback(() => {
  update(prev => ({ ...prev, flag: !prev.flag }))
},[])
const handleIncrement = useCallback(() => {
  update(prev => {
    if (!prev.flag) return prev
    return { ...prev, count: prev.count + 1 }
  })
},[])

Hooks 記事では言う必要もなく、これは現時点での考察になりますのでご注意下さい。