react-hooksのuseStateでfunctionを管理させたい場合のTips
react-hooksのuseStateでfunctionを管理させたい場合のTips:
react-hooksの
例えば単純なカウンターならこんな具合になるだろう
この
例えばこんな風に書くと、意図しない挙動になるだろう。
おそらくこのようにすると、
結論から言えば
https://reactjs.org/docs/hooks-reference.html#functional-updates
Functional Update自体は便利で、下記のように、現在の値を引き継がずに関数だけで利用することができる
これはhooksで新しく入ったわけではなく、
https://reactjs.org/docs/react-component.html#setstate
ただComponentの場合はstate自体がobjectなのでほとんどこのような引っかかり方をすることは無かった。
react-hooksの
useStateはこれまでのstateのように値を保持してくれる重要な関数だ。例えば単純なカウンターならこんな具合になるだろう
const useCounter = () => {
const [count, setCounter] = useState(0)
return { count, setCounter
}
export const MyApp = () => {
const { count, setCounter } = useCounter()
return (
<div>
<div>{count}</div>
<button onClick={() => setCounter(count + 1)}>+</button>
</div>
)
}
useStateに関数を保持させたい場合、ちょっと注意が必要になる。例えばこんな風に書くと、意図しない挙動になるだろう。
const initialHelloFn = () => {
console.log("initial")
}
const useCounter = () => {
const [count, setCounter] = useState(0)
const [helloFn, setHelloFn] = useState(initialHelloFn)
// このnewFnが何度も呼び出される
const newFn = useCallback(() => {
console.log("hello!", count)
}, [count])
useEffect(() => {
setHelloFn(newFn)
}, [newFn, setHelloFn])
console.log(helloFn)
return {
count,
setCounter,
helloFn
}
}
export const MyApp = () => {
const { count, setCounter, helloFn } = useCounter()
return (
<div>
<div>{count}</div>
<button onClick={() => setCounter(count + 1)}>+</button>
<button onClick={() => helloFn()}>hello</button>
</div>
)
}
hello! 0のような出力が大量に出てしまうだろう
正しく動かす場合はどうするか?
{fn: 管理したい関数} のようにobjectで管理する。const useCounter = () => {
const [count, setCounter] = useState(0)
// {fn: Function}などobjectの形にラップする
const [helloFn, setHelloFn] = useState({ fn: initialHelloFn })
const newFn = useCallback(() => {
console.log("hello!", count)
}, [count])
useEffect(() => {
setHelloFn({ fn: newFn })
}, [newFn, setHelloFn])
return {
count,
setCounter,
helloFn: helloFn.fn
}
}
なぜこうする必要があるか?
結論から言えばuseStateから返ってくるsetFooのようなハンドラーはFunctional Updateに対応しているため、単純に関数を渡してしまうとFunctional Updateとして処理されてしまうからになる。https://reactjs.org/docs/hooks-reference.html#functional-updates
Functional Update自体は便利で、下記のように、現在の値を引き継がずに関数だけで利用することができる
<button onClick={() => setCount(prevCount => prevCount + 1)}>+</button>
React.Component.setStateにも同様の機能が存在していたものだhttps://reactjs.org/docs/react-component.html#setstate
ただComponentの場合はstate自体がobjectなのでほとんどこのような引っかかり方をすることは無かった。
useStateが単純な値を格納するものとして利用できてる分、この点は気をつけるべき部分だろう
コメント
コメントを投稿