なぜデバッグって難しいのだろう
新人時代、とあるバグを見つけるのに丸一週間かかった記憶があります。最初に試したのは「とりあements problem」でしたが、どこが悪いのかわからず、結局原因不明のまま放置していました。あの頃の自分に、「とりement problemだけじゃなくて、ちゃんとコードを追えばわかるのに」と声をかけたいです。Reactは「宣言的」な記述方法をとるため、期待通りに動作しないとき、どこが変わったのかを追うのが少し手間取ります。特にバグが小さいときは、自分が何をしたかを振り返らずに症状だけを見てしまいます。「ここがおかしい気がする」と表面的な部分だけで終わってしまいがちです。
✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨
最新ツール・トレンド情報をずんだもん×めたんが解説するYouTubeチャンネルを運営しています!
いいね、チャンネル登録してもらえると嬉しいです🙇♂️
ハジメル.dev: https://hajimeru-dev.vercel.app/
「ひとりで続けるのは難しい」「何から学べばいいか分からない」という方向けに、
プログラミングのマンツーマンレッスンサービス「ハジメル.dev」も運営しています。
未経験OK・オンライン完結・月額制/違約金なしなので、気軽に無料相談してみてください🙇♂️
海外テックニュースを追いたいけど、英語や情報量の多さで大変…という方向けに、
Hacker News の話題を日本語でサクッと追える「HackerNews 日本語まとめ & AI要約」
を個人開発しました!
技術トレンド収集に使ってもらえると嬉しいです🔥🙇♂️
→ HackerNews 日本語まとめ & AI要約: https://hn-matome-2ht.pages.dev/
「ニャンパイアサバイバー」というヴァンパイアサバイバーリスペクトのゲームを作成しました!
もしよろしければ遊んで頂けると嬉しいです😭
習い事教室の先生向けに、SNS 投稿・生徒募集・保護者通知の文章を AI で生成する Web サービス「おしらせAI」を個人開発しました。Next.js + Supabase + LLM で構成しており、無料で月 10 回まで試用できます。よければ触ってみてください。
→ おしらせAI: https://oshirase-ai.vercel.app/
言いたいことがうまく伝わらない…という方向けに、会話の言い方を添削する「伝え方ラボ」を開発中です。
場面を選んで自分の言葉で返すと、何が伝わっていないかの指摘と、そのまま使える言い換えが返ってきます。
ChatGPT に相談すると褒めから入って直すべきところが残りがちなので、指摘側に振り切りました。
現在は公開時にお知らせするメール登録のみ受付中です🙇♂️
→ 伝え方ラボ: https://tsutaekata-lab.pages.dev/
✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨
第一に大切なことは、根本原因を理解すること
僕が初めてつまずいたのは、useStateの初期化値が意図通りにならなかったときでした。計算結果をstateに保存しようと思って、calcValue()関数を定義したのですが、呼び出された瞬間にstateが更新されるため、calcValue()の計算結果自体は反映されませんでした。calcValue()関数が実行されるたびに、stateの値が毎回計算されてしまうのです。つまり、calcValue()の呼び出し側と、calcValue()内で更新するstateが別々に行われていました。
import { useState } from 'react';
function App() {
const [value, setValue] = useState(null);
const calcValue = () => {
setValue(42); // 呼び出し側で更新
};
return <button onClick={calcValue}>計算</button>;
}
このコードは単純に見えますが、buttonのonClickでcalcValue()を呼び出すたびにvalueが42に更新されます。setterを呼ぶたびにstateが更新されるため、計算結果が反映されません。解決策は、stateに計算結果を保存するのではなく、calcValue()内でcalcValueの計算結果を直接使用するか、useEffectでcalcValue()の結果をstateに反映させるかのいず方式です。前者ならcalcValue()を呼ぶたびにvalueが変わりますし、後者ならcalcValue()の呼び出しとstateの更新が分離されます。
第二に、エラーメッセージを侮らないこと
僕は「エラーメッセージが出ていても、とりあements problemで解決できる」と思い込んでいました。しかし、あるときuseEffect内でAPIコールバックを呼び出すコードを書いたところ、callback内でuseStateのsetterを呼び出してしまいました。React Hooksのルールにより、component内部で副作用を扱う際はuseEffectなどの特殊構文を使用しなければなりません。setterを直接呼び出すと「Invalid useEffect callback return value」というエラーが出ました。このエラーは「useEffectの戻り値が関数でない」ことを指摘しています。setterを呼び出さないように修正することで、症状はすぐに改善しました。エラーメッセージは英語で書かれていることが多いですが、そのまま翻訳するのではなく、文脈を汲み取って原因を特定する必要があります。
第三に、開発環境を整えること
僕が昔、「とりements problem」のインストラクターとして活躍してくれたのは、VS Codeでしたが、エディタ上部の「Run and Debug」パネルを有効活用していませんでした。デバッグ用のブレクトークポイントを設定し、変数の値を確認するだけで、数千行あるコードの中からバグの简を一発で見つけられるようになります。また、React DevToolsというブラ拡張機能を使うと、コンポーンスpecificなプロセスpecificな状態やpropsを確認できます。僕は最初からDevToolsを使っていたら、前述のuseStateの初期化値のバグももっと早く発見できたはずです。開発環境は「とりements problem」だけではなく、デバッグツールも含めて、最初から丁に整えることが重要です。
第四に、小さな変更を積み重ねること
僕は一度に全体を書き直す癖がありました。バグが発生している部分を一括で修正しようとして、かえって複雑になってしまうことが多かったです。修正案は、特定の機能単位で部分的に修正し、徐々に全体を修正していくことです。例えば、useStateの初期化値をnullにしたあと、徐々に適切な初期値に変更していきます。この方法は時間がかかりますが、原因简が明確になりやすく、後で修正する範囲が限定されます。小さな変更を繈的に行うことで、バグの修正が安定しやすくなります。
第五に、他人のコードを読むこと
僕はチーム内でコードレビューを依頼するのが苦手でした。しかし、ある案件でバグを発見した後、先輩エンナーが作成した同様の機能のコードを見せてもらい、useCallbackとuseMemoの使い方を学びました。useCallbackはcallbackの参照を保持し、不要な再描画を防ぐことができます。useMemoは計算結果をキャッシュし、再計算を防ぐことができます。これらのテクニックは、バグの修正だけではなく、パフォーマンスの向上にも役立ちます。他人のコードを読むことで、自分の視野が広がり、新しい気づきを得ることができます。
まとめ
Reactのデバッグは、とりements problemだけではなく、根本原因の理解、エラーメッセージの読み取り、開発環境の整備、小さな変更の積み重ね、他人のコードの読むといった地道な努力が必要です。僕は最初つまずいたuseStateの初期化値のバグも、DevToolsと修正案で解決しました。初心者はつまずきやすいですが、根気よく修正していくうちに、バグの修正力も身につきます。少し先を歩いている先輩として、皆さんにも地道な努力を推埋します。