【入門編】 useEffectの過剰使用(Over-using)とリファクタリング – React実践ガイド

こんにちは、現場の最前線でReactのコードと格闘し続けているチーフアーキテクトです。

Reactを学び始めたばかりの頃、誰もが一度は「魔法の杖」のように頼ってしまうフックがあります。そう、`useEffect`です。

「値が変わったら、何かをする」——。この考え方は直感的で分かりやすいため、ついつい何でもかんでも`useEffect`の中に詰め込みたくなってしまいますよね。でも、実はそこに「同期の罠」が潜んでいます。

今日は、初心者の方が一番つまずきやすく、そしてプロへの第一歩として必ず通る道である「useEffectの過剰使用(Over-using)」について、お買い物の例え話を交えながら、優しく紐解いていきましょう。

大丈夫、これを読み終える頃には、あなたの書くコードはもっとスッキリ、もっと軽やかになっているはずですよ。

—

1. 注文した後に「あ、これも!」は二度手間?

想像してみてください。あなたは近所のカフェで、コーヒー(500円)とケーキ(600円)を注文しました。

【useEffectを使いすぎている状態】
1. 店員さんがコーヒーとケーキをテーブルに運んできます。
2. テーブルに置いたあと、店員さんは「あ、合計金額を計算しなきゃ」とレジに戻ります。
3. 計算して「合計1,100円です!」と伝えに、またテーブルに戻ってきます。

これ、どう思いますか? 「いや、持ってくる時に計算しておいてよ!」って思いますよね(笑)。

Reactの世界でも同じことが起きています。
`useEffect`を使って「名前が変わったから、フルネームを更新する」「価格が変わったから、合計額を更新する」という処理を書くと、Reactは一度画面を描画した後に、もう一度計算のために描き直すという二度手間(再レンダリング)を発生させてしまうのです。

—

2. 「レンダリング中に計算する」という魔法

Reactの基本は、「データ(PropsやState)を入力したら、出力(UI)が決まる」というシンプルな関数の形です。

わざわざ「描き終わった後(useEffect)」に何かを書き換えるのではなく、「描いている最中」に計算を済ませてしまえばいいのです。

まずは、ついついやってしまいがちな「アンチパターン(良くない例)」から見てみましょう。

✕ もったいないコード(useEffectの使いすぎ)

import React, { useState, useEffect } from ‘react’;

function ShoppingCart() {
const [price, setPrice] = useState(0); // 商品の単価
const [quantity, setQuantity] = useState(1); // 個数
const [total, setTotal] = useState(0); // 【罠】合計金額をわざわざStateにしている

// ✕ 単価や個数が変わるたびに、useEffectで合計を計算している
useEffect(() => {
setTotal(price quantity);
// これだと、「描画 → useEffect実行 → 再描画」と2回動いてしまう!
}, [price, quantity]);

return (

setPrice(Number(e.target.value))} />
setQuantity(Number(e.target.value))} />

合計金額: {total}円

);
}

このコードの何がいけないのか。それは、`total`という「他の値(priceとquantity)から計算できるもの」を、わざわざ独立したStateにしてしまっている点です。

これを、プロの書き方にリファクタリングしてみましょう。

〇 理想的なコード(直接計算)

import React, { useState } from ‘react’;

function ShoppingCart() {
const [price, setPrice] = useState(0);
const [quantity, setQuantity] = useState(1);

// ◎ useEffectを使わず、レンダリングの中で直接計算する!
// これなら「描画」の1回だけで完璧な結果が表示されます。
const total = price quantity;

return (

setPrice(Number(e.target.value))} />
setQuantity(Number(e.target.value))} />

合計金額: {total}円

);
}

どうですか? `useEffect`も`setTotal`も消えて、コードが驚くほどスッキリしましたね。
「計算できるものは、その場で計算する」。これがReactを使いこなすための最初にして最大の秘訣です。

—

3. 計算がとっても大変な時は「useMemo」の出番

「でも先生、その計算がめちゃくちゃ重くて、毎回計算してたら画面がカクカクしちゃう時はどうすればいいんですか?」

鋭い質問ですね! その通り。例えば、何万件もあるデータの中から特定の文字で検索(フィルタリング)するような処理は、毎回やるのは大変です。

そんな時に使うのが、`useMemo`(ユーズ・メモ)です。
これは「計算結果のメモ帳」のようなもの。「材料(依存配列)が変わっていないなら、前回の計算結果を使い回してね」とReactにお願いする道具です。

実用例:リストのフィルタリング

import React, { useState, useMemo } from ‘react’;

function UserList({ users }) {
const [query, setQuery] = useState(”);

// ユーザーのリストから、入力された文字に合う人だけを絞り込む
// この計算を「メモ化」します
const filteredUsers = useMemo(() => {
console.log(‘一生懸命、計算中…’);
return users.filter(user => user.name.includes(query));
}, [users, query]); // usersかqueryが変わった時だけ、再計算するよ!

return (

setQuery(e.target.value)}
/>

    {filteredUsers.map(user => (

  • {user.name}
  • ))}

);
}

ここでも`useEffect`は使いません。`useMemo`を使うことで、不必要な再描画を防ぎつつ、計算コストも最小限に抑えることができるのです。

—

4. 迷った時の合言葉:「それはPropsやStateから作れる?」

Reactを書いていて「ここ、useEffectかな?」と思ったら、自分にこう問いかけてみてください。

「今作ろうとしている値は、既存のPropsやStateを組み合わせるだけで計算できるかな?」

もし答えが「Yes」なら、`useEffect`は不要です。

  • 氏名 + 名 = フルネーム → 直接計算でOK
  • 価格 × 消費税 = 税込価格 → 直接計算でOK
  • 全データ + 検索ワード = 絞り込み結果 → 直接計算(またはuseMemo)でOK

`useEffect`の本来の役割は、Reactの世界の外側(APIでデータを取る、ブラウザのタイトルを変える、タイマーをセットする等)と繋がること。

「React内部のデータ同士を同期させるため」に使うのは、卒業してしまいましょう!

—

終わりに

最初はみんな、`useEffect`をたくさん書いてしまいます。私もそうでした。
でも、コードが複雑になってきたときに「あ、これ計算できるじゃん!」と気づいて消していく作業は、パズルが解けるようでとても気持ちいいものです。

もし失敗して画面が真っ白になっても、無限ループになっても大丈夫。それはあなたが「より良い書き方」を探求している証拠ですから。

一歩ずつ、楽しみながらコードを綺麗にしていきましょう。応援していますよ!

コメント

タイトルとURLをコピーしました