【React】useEffect(副作用)の多用はやめよう
2022/10/05
ReactのuseEffect
便利ですよね。
自分もよくお世話になっていますが、なまじ便利すぎるがゆえに必要ないケースでもuseEffect
が使われているコードが見られます。
関数型プログラミングに影響を受けているReactにおいて、useEffect
(副作用)の多用はあまりよくないとされているのですが、その理由を具体例をもとに紹介します。
useEffectを多用した例
useEffect
を使わない場合と比較するために、あえてuseEffect
を多用した例を紹介します。
↓はcount1
の増加に応じてcount2
, count3
, count4
が変化するコードです。
EffectExample.tsx
import React, { useEffect, useState } from 'react'
const EffectExample: React.FC = () => {
const [count1, setCount1] = useState(0)
const [count2, setCount2] = useState(0)
const [count3, setCount3] = useState(0)
const [count4, setCount4] = useState(0)
const onClickAdd = () => {
setCount1((prev) => prev + 1)
}
const onClickReset = () => {
setCount1(0)
}
useEffect(() => {
setCount2(count1 * 2)
}, [count1])
useEffect(() => {
setCount3(count2 * count2)
}, [count2])
useEffect(() => {
setCount4(count2 + count3)
}, [count2, count3])
return (
<div>
<ul>
<li>count1: {count1}</li>
<li>count2: {count2}</li>
<li>count3: {count3}</li>
<li>count4: {count4}</li>
</ul>
<button onClick={onClickAdd}>ADD</button>
<button onClick={onClickReset}>RESET</button>
</div>
)
}
export default EffectExample
どうでしょうか? ロジック自体はかなりシンプルなはずなのに若干ロジックが追いづらく見えます。
「こんなuseEffect
の使い方しないよ」と思われるかもしれませんが、一つのコンポーネントにuseEffect
が多くある場合は結構上の例みたいになってる場合が多いです。
useEffectなしの例
今回の例の場合ではわざわざuseEffect
を使う必要がありません。
NoEffectExample.tsx
import React, { useState } from 'react'
const NoEffectExample: React.FC = () => {
const [count1, setCount1] = useState(0)
const [count2, setCount2] = useState(0)
const [count3, setCount3] = useState(0)
const [count4, setCount4] = useState(0)
const onClickAdd = () => {
const newCount1 = count1 + 1
const newCount2 = newCount1 * 2
const newCount3 = newCount2 * newCount2
const newCount4 = newCount2 + newCount3
setCount1(newCount1)
setCount2(newCount2)
setCount3(newCount3)
setCount4(newCount4)
}
const onClickReset = () => {
setCount1(0)
setCount2(0)
setCount3(0)
setCount4(0)
}
return (
<div>
<ul>
<li>count1: {count1}</li>
<li>count2: {count2}</li>
<li>count3: {count3}</li>
<li>count4: {count4}</li>
</ul>
<button onClick={onClickAdd}>ADD</button>
<button onClick={onClickReset}>RESET</button>
</div>
)
}
export default NoEffectExample
useEffect
を多用する場合と比較してcount2
, count3
, count4
の変化が追いやすいと思います。
またcount2
, count3
, count4
変化のタイミングがADDボタンとRESETボタンを押したタイミングであるということがコードからわかりやすいのもポイントです。
まとめ
まとめるとuseEffect
を多用するデメリットは以下のとおりです。
- ロジックが追いづらく、同期的に処理されるわけではないのでバグの温床になりうる
- 副作用の連鎖により、
useEffect
発火のタイミングがわかりづらくなる
useEffect
を使用する際には、本当にuseEffect
を使う必要があるのかな?と考えるといいかもしれません 🤨