はじめに
初めてReactを勉強し、おそらくすぐに登場するであろう「useEffect」
当時はuseEffectを定義したコンポーネントがマウントされたタイミングで実行される関数&依存配列内の値に変更があった場合に再実行(再レンダー)される関数、くらいに思っていました。
が、社内の勉強会で下記を読んで昨今議論されている「useEffectみんな間違った使い方しすぎ」問題がなんとなく理解できたので整理します
どうでもいいですが公式サイトのパンクズを翻訳すると「避難ハッチ」という単語が出てきており、初見ではただならぬ不穏さを感じたのが良い思い出です

エフェクトとは何か
以下公式サイトから引用
エフェクトは、特定のイベントによってではなく、レンダー自体によって引き起こされる副作用を指定するためのものです。チャットでのメッセージ送信は、ユーザが特定のボタンをクリックすることによって直接引き起こされるため、イベントです。しかし、サーバ接続のセットアップは、コンポーネントが表示される原因となるインタラクションに関係なく行われるべきであるため、エフェクトです。エフェクトは、コミットの最後に、画面が更新された後に実行されます。ここが、React コンポーネントを外部システム(ネットワークやサードパーティのライブラリなど)と同期させるのに適したタイミングです。
重要なキーワードとしては
- 特定のイベントによってではなく、レンダー自体によって引き起こされる
- 副作用
- React コンポーネントを外部システムと同期させる
かなと思います!
そのエフェクトは不要かも
公式ドキュメントの
「You Might Not Need an Effect」
が伝えたい一番大きなメッセージはこれです。
よくある間違い①:state から state を作る
const [fullName, setFullName] = useState('')
useEffect(() => {
setFullName(`${firstName} ${lastName}`)
}, [firstName, lastName])
これは一見正しそうに見えますが、
state から派生する値をわざわざ state にしているのが問題です。
正解はこちらです。
const fullName = `${firstName} ${lastName}`
計算で求まるものは state にしないことで
余計なstate管理も減らせますし、再レンダーも1回で済みます
また、コンポーネント内部stateの修正などはエフェクトとして不適切とされています。
よくある間違い③:イベントで起きる処理を useEffect に書く
useEffect(() => {
if (isSubmitted) {
submitForm()
}
}, [isSubmitted])
これはイベント駆動なのにエフェクトを使っている状態です。
再掲ですが、エフェクトは、特定のイベントによってではなく、レンダー自体によって引き起こされる副作用を指定するためのものです。
通常のイベントであれば下記のように書くのが良いです
const handleSubmit = () => {
submitForm()
}
useEffectを使うべき場面
① 外部システムとの同期
useEffect の本来の役割です。下記の例だと、コンポーネントがレンダーされる際にsocketのコネクションを作成する動作になります。
useEffect(() => {
const socket = createConnection()
socket.connect()
return () => {
socket.disconnect()
}
}, [])
useEffectの使用用途として、Reactコンポーネントを外部システム(ネットワークやサードパーティのライブラリなど)と同期させる、が本来適しています。
② データフェッチ(ただし注意)
useEffect(() => {
fetchData()
}, [userId])
上記のようにコンポーネントがレンダーされたタイミングでユーザーデータをサーバー(外部システム)から取得するなどもOKです。(Reactコンポーネントを外部システムと同期させる)
ただし、最近は以下が推奨されがちです。
- React Query
- RTK Query
- SWR
おわりに
最後まで読んでいただきありがとうございます!
社内で公式ドキュメント読み合わせ会を行った際に今回の記事を読み、整理してみました!
これまでは結構特にここまで考えずにuseEffectを使っていたので、気をつけないとと思いました・・・。