はじめに
こちらの講義(Echo/Go + Reactで始めるモダンWebアプリケーション開発)を学んでいてフロントエンドの基本を抑える必要があると思い表面的に少し学んだのでその備忘録として記録しています。今後も知った内容は追加していきます。
基本整理
基本
概念としては大きくわけて以下のUIロジックとビジネスロジックの2つが存在する。
- UIロジック:コンポーネントの描画、イベントハンドリング、ライフサイクル管理
- ビジネスロジック:データの処理、状態管理、APIとの通信
用語整理
-
ライフサイクル管理:コンポーネントが生成されてから破棄されるまでの一連の段階(マウント、更新、アンマウント)において、特定の処理を実行する仕組み。
- マウント時: 初期化処理やデータ取得を実施。
-
更新時: propsやstateの変更に基づく再描画と必要な再処理を実行。
- props:親コンポーネントから子コンポーネントに渡されるオブジェクトや配列、関数などのJavaScriptの値などといった情報のこと。
-
state:コンポーネントが内部で持つ状態のこと。
- 状態:動的データ(ユーザーの操作や外部からのデータ取得など)の保持。この状態が更新されると、Reactがその変化を検知して自動的に再レンダリングを行い最新の状態に基づいたUIを表示する。useStateフックを使って状態管理するのが普通。このようにReactコンポーネントは内部で状態を管理して、各コンポーネントには独自の状態があり、それらをレンダリングし必要に応じて再描画している。
- アンマウント時: イベントリスナー解除、タイマーのクリアなどクリーンアップ処理を行い、不要な参照を解放することでGCが正しく動作するようにする。
-
DOM(特にリアルDOMについて):ブラウザがWebページを読み込む際、HTMLパーサーというものを使って文書の構造(階層とか要素)をツリー上のデータ構造に変換し(DOMツリーを生成するという呼ばれ方感)、それによって生成されたDOMは要素や属性やテキストなどの各部分を開発者がオブジェクトとして扱えるようになっており、Javascriptなどのプログラムから文書の内容や構造やスタイルを動的に変更できるようにする。これはリアルDOMという概念。ただしリアルDOMでは変更があると、DOMツリー全体を読み込むため更新処理が重くなりやすいという問題点がある(部分的な最適化を行うこともあるけど、そもそもDOMの直接操作はコストが高いらしい)。それを改善するのがReactに存在する仮想DOMという概念。
-
仮想DOM:リアルDOMの軽量なコピー(タグ名や属性や子要素など、UIを構成するための必要最低限の情報)をJavaScriptオブジェクトとしてメモリ上に割り当てたもの。仮想DOMがメモリ上に割り当てられるタイミングとしては、初回レンダリング時と、状態やプロパティの変更でコンポーネントが再レンダリングされた時の2パターン。この新旧仮想DOMを比較し、変更の差分を検出してその差分だけを実際のDOM(リアルDOM)に反映する。こうすることで無駄なDOM更新(全体再描画など)を減らし変更差分だけを再描画し、リアルDOMの課題であるパフォーマンスの低下を改善している。差分検出後、不要となった古い仮想DOMは、差分をリアルDOMへ反映した後にGCによって破棄される。
-
捕捉:
-
リアルDOMのみの場合:
- ブラウザがDOMの変更を検知し再レンダリングから再描画までを行う。
-
仮想DOMを用いた場合:
- 「初回レンダリング時はブラウザがリアルDOM生成(Reactのマウントポイントなど最小限のマークアップ)
- Reactが起動し、仮想DOMを生成し差分をリアルDOMに書き込む
- ブラウザがリアルDOMを描画
- Reactがコンポーネントのstateやpropsの変更を検知すると再レンダリングし新しい仮想DOMを生成
- Reactが新旧仮想DOMの差分検出を行い差分のみをリアルDOMに反映(差分以外はリアルDOM上ではそのまま再利用)
- リアルDOMに反映された変更をブラウザが検知して再描画し画面を更新
- GCによって古い仮想DOMを破棄
- 以降4番〜7番のサイクル
-
リアルDOMのみの場合:
- HTMLパーサー:一旦スルー
-
捕捉:
-
フロントエンドにおけるデータの処理:
- バックエンドから受け取ったデータ(JSONなど)をコンポーネントで扱いやすい形に変換する処理
- ユーザーが入力した値のバリデーションやデータの変換処理
- ソートや計算
- 処理されたデータをUIコンポーネントにマッピングする処理
- etc
大まかな流れ
- Reactにおいて、UIはコンポーネントとして分割するもの。
- 分割したコンポーネント毎にそのコンポーネントの視覚的状態を記述。
- その後に分割したコンポーネント同士を接続する。
思想
- 1つのコンポーネントに持たせる機能的な責任は1つだけ。(責任が増えたらまた分割)
各ディレクトリの役割
フロントエンドでは基本的にLayer型とFeature型の2種類もしくは組み合わせるパターンがあるが、今回はそういうの忘れて以下のような各ディレクトリ名やファイル名に与えられる責任について整理。
src/
├── components/
├── hooks/
├── store/
├── types/
├── App.tsx
└── index.tsx
src/
クライアント側の全体ロジック
components/
- メモ: 画面表示・ユーザーの操作、フックの実行タイミングの設定はここでする。
-
依存先:
-
hooks/
に定義されているフック -
store/
から状態を取得・更新
-
-
APIサーバーとの関係:
- 直接APIにはアクセスせず、hooksディレクトリに定義されているフックを呼び出すだけ。
hooks/
- メモ: API通信(実際にHTTPリクエストを実行する処理を書くのはここ)、非同期ロジックなどをここで定義し、他のディレクトリから呼び出してもらって使う。
-
依存先:
-
types/
に定義されている型定義(これを参照してAPIレスポンスを型安全に処理) -
store/
に定義されている状態(これを参照して状態の操作(リセット・更新など)を行う) -
useError
に定義されている共通エラーハンドリング
-
-
APIサーバーとの関係:
- APIに直接アクセス
store/
- メモ: ローカルの状態を保持する
-
依存先:
- なし(他レイヤーに依存しない独立した層)
types/
- メモ: アプリ全体で使われるTypeScriptの型を定義する場所
-
依存先:
- なし(他レイヤーに依存しない独立した層)
App.tsx
- メモ: アプリのルーティングと初期化、レイアウトの定義
-
依存先:
-
components/
をルートごとに表示
-
index.tsx
- メモ: Reactアプリ起動エントリポイント
-
依存先:
-
App.tsx
をルートとして読み込む
-
その他知ったこと
async
非同期関数を定義するためのもの。これを設定することで非同期処理の関数が簡単にかける。
API通信やdbアクセスを非同期で行うと必ずPromiseが返ってくる。Promiseとは非同期処理の結果をあとから受け取る箱(非同期処理の完了(成功or失敗)を表すオブジェクト)。Promiseが返ってくるまではawaitを使って一次停止して待つ。つまり、asyncを使っている関数は必ずawaitを使うぞという宣言でもあり、戻り値はPromiseになる。
なぜ非同期にする?
UX向上のため。
同期処理にしてしまうと登録中画面がフリーズする。
同期でも非同期でも、登録処理自体にかかる時間は同じ(処理内容(API呼び出し → DB登録 → レスポンス)にかかる時間自体は変わらない)。変わるのはその待ってる間に他のことができるかどうか。
非同期にするとこで、例えばサインアップ中でもユーザー操作に応答し続けられる(例:タイムアウト制御、キャンセル処理が可能になる)
イベントとは
ユーザーの操作に対して、何か処理を行うためのトリガー。(onClick、onSubmit、onChange など)
Reactは独自のイベントラッパー(SyntheticEvent)によって統一された扱いができる(どのブラウザでも同じように扱えるようになってる)。TypeScriptで型付けする時には FormEvent, MouseEvent, ChangeEvent とかの種類がある。
イベントオブジェクト(e)
イベントに関する情報の入った箱
React Query
Reactアプリ内でAPIとのデータ取得、キャッシュ管理、ローディング状態、エラーハンドリングなどを簡単にするライブラリで、API通信と状態管理のベストプラクティスが整っている。
カスタムフックとは
自分で定義する再利用可能なReactの関数(基本的にフック名はuseから始める)。
参考
Echo/Go + Reactで始めるモダンWebアプリケーション開発
鋼の意思で実施した、技術的負債解消のためのリアーキテクチャ
フロントエンドのディレクトリ設計思想
React Architecture Pattern and Best Practices in 2025
Vue.js・Reactを触る際に知っておきたい仮想DOMの話
Single-responsibility principle
React Web とネイティブユーザインターフェースのためのライブラリ
Reactのベストプラクティスを模索する
[FE] フロントエンドのディレクトリ設計
React初学者が必ず押さえておきたい考え方とは?【コンポーネント指向のフロントエンド】
Reactのディレクトリ構成について再考する
React プロジェクトのディレクトリ構成
終わりに
状態の理解が浅いので深掘りたい。