クリーンな React コンポーネント通信のためのイベント駆動型アーキテクチャ
React アプリケーションでのプロップのドリルリングとコールバック チェーンの終わりのないもつれにうんざりしていませんか?深くネストされたコンポーネント間の状態と通信の管理は、スパゲッティ コードと格闘するような感じですか?
イベント駆動型アーキテクチャは、コンポーネントの対話を簡素化し、複雑さを軽減し、アプリをより保守しやすくします。この記事では、カスタム useEvent フックを使用してコンポーネントを分離し、React アプリ全体の通信を改善する方法を説明します。
順を追って説明しましょう。まずは
問題: 小道具のドリルリングとコールバック チェーン
現代のアプリケーション開発では、コンポーネント間の状態と通信の管理がすぐに面倒になることがあります。これは、プロップ ドリル (複数レベルのネストされたコンポーネントを介してデータを渡す必要がある場合) や コールバック チェーン を含むシナリオに特に当てはまります。これにより、ロジックが複雑になり、コードの実行が困難になる可能性があります。メンテナンスまたはデバッグ。
これらの課題により、緊密に結合されたコンポーネントが作成されることが多く、柔軟性が低下し、アプリケーション内でデータがどのように流れるかを追跡しようとする開発者にとって認知的負荷が増大します。より良いアプローチがなければ、この複雑さによって開発が大幅に遅くなり、脆弱なコードベースにつながる可能性があります。
従来のフロー: プロップはダウン、コールバックはアップ
典型的な React アプリケーションでは、親コンポーネントが子に props を渡し、子はコールバックをトリガーすることで親に通信を返します。これは浅いコンポーネント ツリーではうまく機能しますが、階層が深くなると、状況が複雑になり始めます。
プロップドリル: データは、最も深いコンポーネントでのみ必要な場合でも、複数のレベルのコンポーネントを介して手動で受け渡す必要があります。
コールバック チェーン: 同様に、子コンポーネントはイベント ハンドラーをツリーの上に転送する必要があり、密結合で保守が難しい構造を作成します。
よくある問題: コールバックの複雑さ
次のシナリオを例に考えてみましょう:
- 親は 子 A にプロップを渡します。
- そこから、プロパティは GrandChildren A/B にドリルダウンされ、最終的には SubChildren N にドリルダウンされます。
- SubChildren N が親にイベントを通知する必要がある場合、コールバック がトリガーされ、各中間コンポーネント を経由して戻ります。
アプリケーションが大きくなるにつれて、この設定の管理は難しくなります。中間コンポーネントは多くの場合、プロップとコールバックを転送する仲介者としてのみ機能するため、コードが肥大化して保守性が低下します。
プロップドリルに対処するために、データ共有を合理化するために、グローバル状態管理ライブラリ (例: Zustand) などのソリューションに頼ることがよくあります。しかし、コールバックの管理についてはどうすればよいでしょうか?
ここで、イベント駆動型のアプローチが変革をもたらす可能性があります。コンポーネントを分離し、イベントに依存してインタラクションを処理することで、コールバック管理を大幅に簡素化できます。このアプローチがどのように機能するかを見てみましょう。
解決策: イベント駆動型アプローチを導入する
ツリー上の通信に直接コールバックに依存するのではなく、イベント駆動型アーキテクチャによりコンポーネントが分離され、通信が集中化されます。仕組みは次のとおりです:
イベントのディスパッチ
SubChildren N がイベント (例: onMyEvent) をトリガーするとき、親のコールバックは直接呼び出されません。
代わりに、集中イベント ハンドラーによって処理されるイベントをディスパッチします。
集中処理
イベント ハンドラーは、ディスパッチされたイベントをリッスンして処理します。
必要に応じて、親 (またはその他の関係するコンポーネント) に通知したり、追加のアクションをトリガーしたりできます。
プロップは下向きのまま
プロパティは引き続き階層の下に渡され、コンポーネントが機能するために必要なデータを確実に受け取ります。
これは、zustand、redux などの集中状態管理ツールで解決できますが、この記事では取り上げません。
実装
しかし、このアーキテクチャをどのように実装すればよいでしょうか?
useイベントフック
useEvent というカスタム フックを作成しましょう。このフックは、イベント サブスクリプションを処理し、ターゲット イベントをトリガーするディスパッチ関数を返す役割を果たします。
typescript を使用しているため、カスタム イベントを作成するにはウィンドウのイベント インターフェイスを拡張する必要があります。
interface AppEvent<PayloadType = unknown> extends Event { detail: PayloadType; } export const useEvent = <PayloadType = unknown>( eventName: keyof CustomWindowEventMap, callback?: Dispatch<PayloadType> | VoidFunction ) => { ... };
そうすることで、カスタム イベント マップを定義し、カスタム パラメーターを渡すことができます。
interface AppEvent<PayloadType = unknown> extends Event { detail: PayloadType; } export interface CustomWindowEventMap extends WindowEventMap { /* Custom Event */ onMyEvent: AppEvent<string>; // an event with a string payload } export const useEvent = <PayloadType = unknown>( eventName: keyof CustomWindowEventMap, callback?: Dispatch<PayloadType> | VoidFunction ) => { ... };
必要なインターフェイスを定義したので、最終的なフック コードを見てみましょう
import { useCallback, useEffect, type Dispatch } from "react"; interface AppEvent<PayloadType = unknown> extends Event { detail: PayloadType; } export interface CustomWindowEventMap extends WindowEventMap { /* Custom Event */ onMyEvent: AppEvent<string>; } export const useEvent = <PayloadType = unknown>( eventName: keyof CustomWindowEventMap, callback?: Dispatch<PayloadType> | VoidFunction ) => { useEffect(() => { if (!callback) { return; } const listener = ((event: AppEvent<PayloadType>) => { callback(event.detail); // Use `event.detail` for custom payloads }) as EventListener; window.addEventListener(eventName, listener); return () => { window.removeEventListener(eventName, listener); }; }, [callback, eventName]); const dispatch = useCallback( (detail: PayloadType) => { const event = new CustomEvent(eventName, { detail }); window.dispatchEvent(event); }, [eventName] ); // Return a function to dispatch the event return { dispatch }; };
useEvent フックは、カスタム ウィンドウ イベントをサブスクライブしてディスパッチするためのカスタム React フックです。これにより、カスタム イベントをリッスンし、特定のペイロードでそれらをトリガーすることができます。
ここで行っていることは非常に単純です。標準のイベント管理システムを使用し、カスタム イベントに対応するためにそれを拡張しています。
パラメータ:
- eventName (文字列): リッスンするイベントの名前。
- callback (オプション): イベントがトリガーされたときに呼び出す関数で、引数としてペイロードを受け取ります。
特徴:
- イベント リスナー: 指定されたイベントをリッスンし、イベントの詳細 (カスタム ペイロード) を使用して提供されたコールバックを呼び出します。
- イベントのディスパッチ: フックは、カスタム ペイロードでイベントをトリガーするディスパッチ関数を提供します。
例:
interface AppEvent<PayloadType = unknown> extends Event { detail: PayloadType; } export const useEvent = <PayloadType = unknown>( eventName: keyof CustomWindowEventMap, callback?: Dispatch<PayloadType> | VoidFunction ) => { ... };
わかりました。でも、どうでしょうか?
現実世界の例?
この StackBlitz をチェックしてください (ロードされない場合は、ここで確認してください)
この簡単な例は useEvent フックの目的を示しています。基本的に本体のボタンは、サイドバー、ヘッダー、およびフッター コンポーネントからインターセプトされたイベントを送出し、それに応じて更新されます。
これにより、多くのコンポーネントにコールバックを伝播することなく、原因/結果反応を定義できるようになります。
useEvent の実世界の使用例
ここでは、useEvent フックが通信を簡素化し、React アプリケーション内のコンポーネントを分離できる、実際の使用例をいくつか示します。
1. 通知システム
通知システムでは、グローバルなコミュニケーションが必要になることがよくあります。
-
シナリオ:
- API 呼び出しが成功すると、アプリ全体に「成功」通知が表示される必要があります。
- ヘッダー内の「通知バッジ」などのコンポーネントも更新する必要があります。
解決策: useEvent フックを使用して、通知の詳細を含む onNotification イベントを送出します。 NoticeBanner や Header などのコンポーネントは、このイベントをリッスンして個別に更新できます。
2. テーマの切り替え
ユーザーがテーマ (ライト/ダーク モードなど) を切り替えると、複数のコンポーネントが応答する必要がある場合があります。
-
シナリオ:
- ThemeToggle コンポーネントはカスタムの onThemeChange イベントを送出します。
- サイドバーやヘッダーなどのコンポーネントはこのイベントをリッスンし、それに応じてスタイルを更新します。
利点: コンポーネント ツリー全体で props を介してテーマの状態やコールバック関数を渡す必要がありません。
3. グローバルキーバインド
「Ctrl S」を押して下書きを保存したり、「Escape」を押してモーダルを閉じるなどのグローバル ショートカットを実装します。
-
シナリオ:
- グローバル キーダウン リスナーは、押されたキーの詳細を含む onShortcutPressed イベントを送出します。
- モーダル コンポーネントまたはその他の UI 要素は、キー イベントの転送を親コンポーネントに依存せずに、特定のショートカットに応答します。
4. リアルタイム更新
チャット アプリやライブ ダッシュボードなどのアプリケーションでは、リアルタイムの更新に反応するために複数のコンポーネントが必要です。
-
シナリオ:
- WebSocket 接続は、新しいデータが到着すると onNewMessage または onDataUpdate イベントを送出します。
- チャット ウィンドウ、通知、未読メッセージ カウンターなどのコンポーネントは、独立して更新を処理できます。
5. コンポーネント間のフォーム検証
複数のセクションを持つ複雑なフォームの場合、検証イベントを一元化できます。
-
シナリオ:
- ユーザーがフィールドに入力すると、フォーム コンポーネントは onFormValidate イベントを送出します。
- 概要コンポーネントは、フォーム ロジックと密接に連携することなく、これらのイベントをリッスンして検証エラーを表示します。
6. 分析の追跡
ユーザーの操作 (ボタンのクリック、ナビゲーション イベントなど) を追跡し、分析サービスに送信します。
-
シナリオ:
- 関連する詳細 (クリックされたボタンのラベルなど) を含む onUserInteraction イベントを送信します。
- 中央分析ハンドラーはこれらのイベントをリッスンし、分析 API に送信します。
7. コラボレーションツール
共有ホワイトボードやドキュメントエディターなどの共同作業ツールの場合、イベントはマルチユーザーの対話を管理できます。
-
シナリオ:
- ユーザーがオブジェクトを描画、入力、または移動するたびに onUserAction イベントを送出します。
- 他のクライアントと UI コンポーネントはこれらのイベントをリッスンして、変更をリアルタイムで反映します。
これらのシナリオで useEvent フックを活用すると、深くネストされた props やコールバック チェーンに依存せずに、モジュール式で保守可能でスケーラブルなアプリケーションを作成できます。
結論
イベントは、複雑さを軽減し、モジュール性を向上させることで、React アプリケーションの構築方法を変革します。小規模から始めて、通信を分離することでメリットが得られるアプリ内のコンポーネントをいくつか特定し、useEvent フックを実装します。
このアプローチを使用すると、コードが簡素化されるだけでなく、将来の保守と拡張も容易になります。
イベントを使用する理由
イベントは、不要な依存関係や複雑なコールバック チェーンを導入することなく、アプリケーション内の他の場所で発生した何かにコンポーネントが反応する必要がある場合に威力を発揮します。このアプローチにより、認知負荷が軽減され、密結合コンポーネントの落とし穴が回避されます。
私のおすすめ
コンポーネント間の通信にはイベントを使用します。コンポーネント ツリー内の位置に関係なく、あるコンポーネントがアクションや状態の変化を他のコンポーネントに通知する必要がある場合に使用します。
コンポーネント内通信、特に密接に関連しているコンポーネントや直接接続されているコンポーネントの通信にイベントを使用することは避けてください。これらのシナリオでは、props、state、context などの React の組み込みメカニズムを利用します。
バランスの取れたアプローチ
イベントは強力ですが、使いすぎると混乱が生じる可能性があります。疎結合コンポーネント間の通信を簡素化するためにこれらを慎重に使用してください。ただし、ローカル インタラクションを管理するための React の標準ツールをそれらに置き換えさせないでください。
以上がクリーンな React コンポーネント通信のためのイベント駆動型アーキテクチャの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ホットAIツール

Undress AI Tool
脱衣画像を無料で

Undresser.AI Undress
リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover
写真から衣服を削除するオンライン AI ツール。

Clothoff.io
AI衣類リムーバー

Video Face Swap
完全無料の AI 顔交換ツールを使用して、あらゆるビデオの顔を簡単に交換できます。

人気の記事

ホットツール

メモ帳++7.3.1
使いやすく無料のコードエディター

SublimeText3 中国語版
中国語版、とても使いやすい

ゼンドスタジオ 13.0.1
強力な PHP 統合開発環境

ドリームウィーバー CS6
ビジュアル Web 開発ツール

SublimeText3 Mac版
神レベルのコード編集ソフト(SublimeText3)

JavaScriptの範囲は、グローバル、機能、およびブロックレベルの範囲に分割される変数のアクセシビリティ範囲を決定します。コンテキストは、この方向を決定し、関数呼び出し方式に依存します。 1.スコープには、グローバルスコープ(どこでもアクセス可能)、関数スコープ(関数内でのみ有効)、およびブロックレベルのスコープ(letとconstは{}内で有効です)が含まれます。 2。実行コンテキストには、変数オブジェクト、スコープチェーン、およびこの値が含まれます。これは、通常の関数におけるグローバルまたは未定義を指します。メソッドコールはコールオブジェクトを指し、コンストラクターは新しいオブジェクトをポイントし、call/apply/bindで明示的に指定することもできます。 3。閉鎖とは、外部スコープ変数へのアクセスと記憶の関数を指します。それらはしばしばカプセル化とキャッシュに使用されますが、引き起こす可能性があります

選択したラジオボタン値を取得するための2つのコアメソッドがあります。 1. QuerySelectorを使用して選択したアイテムを直接取得し、入力[name = "your-radio-name"]を使用します:選択した要素を取得し、その値属性を読み取ります。最新のブラウザに適しており、簡潔なコードがあります。 2。document.getElementsbyNameを使用して、ループノデリストを介して最初にチェックされた無線を見つけて見つけ、その値を取得します。これは、古いブラウザーと互換性がある、またはプロセスの手動制御が必要なシナリオに適しています。さらに、名前属性の綴り、選択されていない状況の処理、およびコンテンツの動的な負荷に注意を払う必要があります

VUE3のCompositapiは、複雑なロジックとタイプの導出により適しており、OptionsAPIはシンプルなシナリオや初心者に適しています。 1。OptionsAPIは、データやメソッドなどのオプションに従ってコードを整理し、明確な構造を持っていますが、複雑なコンポーネントは断片化されています。 2。CompusitionAPIは、セットアップを使用して関連ロジックを集中させます。これは、メンテナンスと再利用を助長します。 3。CompusitionAPIは、混合性機能を介して競合のないパラメーター化可能な論理再利用を実現します。これは、混合物よりも優れています。 4。CoputionAPIは、TypeScriptとより正確なタイプの派生をより適切にサポートしています。 5。2つのパフォーマンスとパッケージングのボリュームに大きな違いはありません。 6。

JavaScriptのWebworkersとJavathreadsの同時処理には本質的な違いがあります。 1。JavaScriptは、単一スレッドモデルを採用しています。 Webworkersは、ブラウザによって提供される独立したスレッドです。これは、UIをブロックしないがDOMを操作できない時間のかかるタスクを実行するのに適しています。 2。Javaは、複雑な同時ロジックとサーバー側の処理に適した、スレッドクラスを通じて作成された言語レベルからの実際のマルチスレッドをサポートしています。 3。ウェブワーカーは、PostMessage()を使用してメインスレッドと通信します。これは非常に安全で孤立しています。 Javaスレッドはメモリを共有できるため、同期の問題に注意する必要があります。 4。ウェブワーカーは、画像処理などのフロントエンドの並列コンピューティングにより適しています。

複雑なJavaScriptアプリケーションをデバッグするには、体系的な使用ツールが必要です。 1.ブレークポイントと条件付きブレークポイントを設定して、条件に応じて、関数入力、ループ、非同期コールバック、フィルターなどの疑わしいプロセスを傍受します。 2.ブラックボクシング機能がサードパーティライブラリの干渉をブロックできるようにします。 3.デバッガーステートメントを使用して、環境判断に基づいてデバッグエントリを制御します。 4.コールスタックを介してコールリンクをトレースし、実行パスと変数ステータスを分析し、それにより問題の根本原因を効率的に見つけます。

タイプキャストとは、JavaScriptの1つのタイプの値を別のタイプに自動的に変換する動作です。一般的なシナリオには次のものが含まれます。1。オペレーターを使用する場合、一方が文字列である場合、反対側も「5」などの文字列に変換されます。結果は「55」です。 2。ブールのコンテキストでは、非ブールの値は、空の文字列、0、ヌル、未定義などのブール型に暗黙的に変換されます。 3. Nullは数値操作に参加し、0に変換され、未定義はNANに変換されます。 4.暗黙の変換によって引き起こされる問題は、number()、string()、boolean()などの明示的な変換関数によって回避できます。これらのルールをマスターすることは役立ちます

JavaScriptのフォーマット日付は、ネイティブメソッドまたはサードパーティライブラリを使用して実装できます。 1.ネイティブの日付オブジェクトのステッチ:GetFullyear、GetMonth、GetDate、その他の方法を介して日付部分を取得し、軽量のニーズに適しており、サードパーティのライブラリに依存しないYyyy-MM-DDおよびその他の形式に手動でスプライスします。 2。TolocaledAtestringメソッドの使用:地元の習慣に応じてMM/DD/YYYY形式などの出力を出力できます。 3. day.jsやdate-fnsなどのサードパーティライブラリを使用:頻繁な操作に適した簡潔な構文とリッチ関数を提供します。

プロジェクトを初期化し、package.jsonを作成します。 2。シバンを使用してエントリスクリプトindex.jsを作成します。 3。Package.jsonのBin Fieldsを介してコマンドを登録します。 4. Yargsおよびその他のライブラリを使用して、コマンドラインパラメーターを解析します。 5。NPMLINKローカルテストを使用します。 6.エクスペリエンスを強化するためのヘルプ、バージョン、オプションを追加します。 7.オプションでnpmpublishを介して公開します。 8.オプションでYargsを使用して自動完成を達成します。最後に、合理的な構造とユーザーエクスペリエンスの設計を通じて実用的なCLIツールを作成し、自動化タスクを完了し、ウィジェットを配布し、完全な文で終了します。
