👋
不要なuseState、useEffectを乱発しない。
Reactはじめたてで、useState、useEffect理解した!楽しい!
ってなって無駄に使った自戒の話です。
不要なuseState、useEffectを乱発した際の実例を紹介したいと思います。
実例
記事のデータ一式を受け取り、それを加工して表示します。
データ
- releaseData : APIから受け取った記事データ一式
- firstData : releaseDataからslugが一致したデータを抽出
- secondData : firstDataからflagが一致したデータを抽出
- finalData : secondDataから条件が一致したデータを抽出。このデータを画面に描画する。
ダメな処理
今見たらこりゃダメなのはわかるのですが、当時はよく分かってなくて逆に処理の流れわかりやすくなった!と思ってました。
const [releaseData,setReleaseData] = <Data[]>([])
const [firstData,setFirstData] = <Data[]>([])
const [secondData,setSecondData] = <Data[]>([])
const [finalData,setFinalData] = <Data[]>([])
// firstDataを抽出する処理
useEffect(() => {
newFirstData = prossessing(releaseData)
setFirstData(newFirstData)
}, [releaseData])
// secondDataを抽出する処理
useEffect(() => {
newSecondData = prossessing(firstData)
setSecondData(newSecondData)
}, [firstData])
// finalDataを抽出する処理
useEffect(() => {
newFinalData = prossessing(secondData)
setFinalData(newFinalData)
}, [secondData])
これが原因で以下のようは弊害が発生しました。
- 無駄にリソースを消費する。
上記のような処理をするとそれぞれの処理が並列で走ってしまうため、releaseData
が更新されても他のuseEffect内で走っている処理が続行されてしまい無駄にリソースを消費してもっさりとした動きになってしまいました。 - 連鎖的な副作用によるデータの不整合
並列して走っていると何かのきっかけでデータに不整合が発生しやすくなりエラーの温床となります。 - デバッグが困難になった。
エラーが発生した際にプログラム側の処理が原因なのかわかりにくく、デバッグを困難にしてしてしまいました。
見直し後の処理
本当に必要なデータはfinalDataのみで、中間加工データはstate保持する必要がなかったため、全ての処理をまとめました。
const [releaseData,setReleaseData] = <Data[]>([])
const [finalData,setFinalData] = <Data[]>([])
// finalDataを抽出する処理
useEffect(() => {
const newFirstData = prossessing(releaseData)
const newSecondData = prossessing(newFirstData)
const newFinalData = prossessing(newSecondData)
setFinalData(newFinalData)
}, [releaseData])
このようにすることでreleaseData
が更新された際に全ての処理が最初から再開され、正常な結果を受け取ることができました。
Discussion