106
51

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

React Hooks、useStateの更新関数引数には関数を

Posted at

最近 Hooks を触って思ったことを綴ります。よく見る useState の increment 例です。

const [count, setCount] = useState(0)
const handleClick = () => {
  setCount(count + 1)
}
return (
  <div className={props.className}>
   <p>count: {count}</p>
   <button onClick={handleClick}>+1</button>
  </div>
)

これはアンチパターンで、handleClick は render毎に再定義されます。この再定義を skip するため、useCallback による関数memoizeを行います。

アンチパターン集

// memoize input array の指定がないため、上記と差がない
const handleClick = useCallback(() => {
  setCount(count + 1)
})
// memoize されているが、状態変化とともに再定義される
const handleClick = useCallback(() => {
  setCount(count + 1)
},[count])
// 2回目以降のレンダリング時再定義が skip されるが
// 初期状態を参照しているため「1」にしかならない。
const handleClick = useCallback(() => {
  setCount(count + 1)
},[])

現状良さそうな方法

状態更新関数の引数に与えるものは、プリミティブに限りません。関数を与えることで、prev state を参照出来ます。これにより、初期レンダリング時のみに handleClick関数定義を抑止し、正しく動かすことが出来ます。

// 2回目以降のレンダリング時の再定義が skip され、正しく動く
const handleClick = useCallback(() => {
  setCount(prev => prev + 1)
},[])

useState で生成された関数は、同時に生成された状態を参照しない方が良さそう、という話でした。

106
51
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
106
51

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?