反応自動構築ルーティングの実装

反応自動構築ルーティングの実装

順序

react-router-dom を使ってプロジェクトを書くと、とても便利に使えると感じますが、主要なルートがさまざまなコンポーネントに分散しているため、メンテナンスが面倒になります。そこで、 react-router-dom に用意されている config モードを使ってルートを記述することを検討します。これの利点は、ロジックを 1 か所に集中させ、ルートをより便利に設定できることです。

プロジェクトギャラリー
https://gitee.com/d718781500/autoRouter

1. 集中ルーティング

まず、/src/router/index.jsに次のデータを定義します。 reactのルーティングの公式ドキュメントには、集中ルーティングを構成するケースが示されています。これは、おおよそ次のようになります。 vueのルーティングに従って、次のような構成ファイルを生成します。

//ルーティング設定が必要です。これは配列です。import Discover from "../pages/Discover"
「../pages/Discover/Djradio」からDjradioをインポートします
「../pages/Discover/Playlist」からプレイリストをインポートします
「../pages/Discover/Toplist」からToplistをインポートします。
「../pages/Friends」からFriendsをインポートします
「../pages/Mine」からMineをインポートします
「../pages/Page404」からPage404をインポートします。
定数ルート = [
    {
        パス: "/friends",
        コンポーネント: 友達
    },
    {
        パス: "/mine",
        コンポーネント: 鉱山
    },
    
    {
        パス: "/discover",
        コンポーネント: 発見、
        子供たち: [
            {
                パス: "/discover/djradio",
                コンポーネント: Djradio
            },
            {
                パス: "/discover/playlist",
                コンポーネント: プレイリスト

            },
            {
                パス: "/discover/toplist",
                コンポーネント: トップリスト
            }
        ]
    },
    この設定はすべてのルーティング設定パスの後になければなりません: "*",
        コンポーネント: ページ404
    }
]

デフォルトルートをエクスポートする

上記の設定を使用してルートを生成することができます。もちろん、上記の設定は単なる単純なプロセスであり、redirect exact などの記述されていない属性がまだあります。簡単なものから始めましょう。

2. ファイルディレクトリ

上記の構成では、vue に似た集中ルーティング構成モードを使用しているため、現在のデモの構造ディレクトリを表示してみましょう。

プロジェクトディレクトリ構造

src/pages ディレクトリ構造

├─発見
│ │ ABC.js
│ │ インデックス.js
│ │
│ ├─DJラジオ
│ │ │ インデックス.js
│ │ │ lf.js
│ │ │
│ │ └─gv
│ │ インデックス.js
│ │
│ ├─プレイリスト
│ │ インデックス.js
│ │
│ └─トップリスト
│ インデックス
│
├─エンターテインメント
│ インデックス
│
├─友達
│ インデックス
│ xb.js
│
├─鉱山
│ インデックス
│
└─404ページ
        インデックス

これらの構造により、1 で説明したインポートされたファイルが混乱することはありません。次に、コンポーネントをカプセル化して CompileRouter という名前を付けることができます。このコンポーネントは、ルートをコンパイルするために特に使用されます。

3. CompileRouterを作成する

このコンポーネントは src/utils に作成します。その機能は、着信ルーティング構成を通じてこのコンポーネントを計算することです。では、なぜこのコンポーネントを作成する必要があるのでしょうか。

React ルーティングの書き方を確認しましょう。React ルーティングには、コーナーストーン コンポーネントに相当する基本コンポーネント HashRouter または BrowserRouter が必要です。また、ルーティング レシピも必要です。このコンポーネントは、コンポーネントをマッピングするパスを受け入れることができます。

これを説明するために疑似コードをいくつか書いてみましょう。

//基本的なルーティングコンポーネントを導入する(プロジェクトにnpm i react-router-domをインストールする)
「react-router-dom」から {HashRouter を Router,Route としてインポートします。
クラスDemoはReact.Componentを拡張します。
    与える(){
        //コーナーストーンルーティング <ルーター>
            //ルーティングレシピコンポーネントはパスによってコンポーネントと一致します
            <ルート パス="/" コンポーネント={ホーム}/>
             <ルート パス="/mine" コンポーネント={Mine}/>
        </ルーター>
    }
}

これが基本的な使用法です。CompileRouter コンポーネントの役割は、上記のコードに示すようにルートを生成し、ルートを生成してコンポーネントに表示することです。Compile の基本的な機能を理解したら、コーディングを始めましょう。私の CompileRouter は、1 のコードに示されている配列のように、ルーティング構成に準拠する配列であるデータを受け入れるように設計されており、受け入れられる属性はルートです。

//このファイルはルート設定を通じてルートをコンパイルします import React from 'react'
「react-router-dom」から Switch、Route をインポートします。
デフォルトのクラスCompileRouterをエクスポートし、React.Componentを拡張します。
    コンストラクタ() {
        素晴らしい()
        この状態 = {
            : []
        }
    }
    レンダリングルート() {
        let {routes} = this.props; //routes ルーティング構成を取得する //1.routes を通じて Route コンポーネントを生成する //routes が配列であることを確認する // console.log(routes)
        //render は、componentDidMount と componentWillUnmount を繰り返し呼び出さない if (Array.isArray(routes) &&routes.length > 0) {
            // 受信ルートが配列であることを確認する // 受信ルートをループする
            finalRoutes = ルート.map(ルート => {
                //各ルートは次のようになります {path:"xxx",component:"xxx"}
                //ルートに子ノードがある場合 {path:"xxx",component:"xxx",children:[{path:"xxx"}]}
                戻り値 <ルートパス={route.path} キー={route.path} レンダリング={
                       // この目的は、ルートにネストされたルートがある場合、ルートの子にある構成データをこのコンポーネントに渡すことができるようにすることです。これにより、コンポーネントは CompileRouter を再度呼び出すときにネストされたルートをコンパイルできます () => <route.componentroutes={route.children} />
                } />
            })

            this.setState({
                c: 最終ルート
            })
        } それ以外 {
            throw new Error('ルートは配列で、その長さは 0 より大きい必要があります')
        }
    }
    コンポーネントマウント() {
        // Route コンポーネントを計算するために renderRoute が最初に呼び出されることを確認します this.renderRoute()
    }
    与える() {
        { c } = this.state; とします。
        戻る (
            <スイッチ>
                {c}
            </スイッチ>
        )
    }
}

上記のコードは、ルート データを処理し、そのようなコンポーネントを宣言するために使用されます。各ステップの役割は上記のコメントでマークしました。

4. CompileRouterを使用する

実際、このカプセル化されたコンポーネントは、vue-router のビュー コンポーネント <router-view/> と見なすことができます。 今のところはこのように考えてみましょう。 次に、ページに第 1 レベルのルートをレンダリングする必要があります。

src/app.js内

'react' から React をインポートします
'react-router-dom' から HashRouter を Router, Link としてインポートします。
//カプセル化された CompileRouter を導入する。import CompileRouter from "./utils/compileRouter"
// 1 で定義されたルーティング構成データをインポートします。importroutes from "./router"
console.log(ルート)
クラスAppはReact.Componentを拡張します。
    与える() {
        戻る (
            <ルーター>
                <Link to="/friends">友達</Link>
                |
                <Link to="/discover">発見</Link>
                |
                <Link to="/mine">私の</Link>
                *vue-router のビュー コンポーネントとして、ルーティング構成データを渡す必要があります*/
                <CompileRouter ルート = {ルート} />
            </ルーター>
        )
    }
}

デフォルトアプリをエクスポート

書き込んだ後、ページは実際にレベル1のルーティングを完全に表示することができます

5. ネストされたルート処理

上で第1レベルのルートをレンダリングしてジャンプできるようになりましたが、第2レベルのルートをどのように処理するのでしょうか?実はこれも非常に簡単です。第2レベルのルートの親ルートを見つけて、CompileRouterを使い続けるだけです。構成から、Discoverルートにはネストされたルートがあることがわかりますので、Discoverルートを例に挙げます。まず、構造図を見てみましょう。

図の index.js は Discover ビュー コンポーネントであり、ネストされたルートの親ルートでもあるため、この index.js で引き続き CompileRouter を使用するだけで済みます。

'react' から React をインポートします
「react-router-dom」から { Link } をインポートします。

「../../utils/compileRouter」からCompileRouterをインポートします。
関数 Discover(props) {

    let {routes} = props //このデータは、ComileRouterコンポーネントがコンパイルされるときに子から渡されます
    // console.log(ルート)
    links = ルート.map(ルート => {
        戻る (
            <li キー = {ルートパス}>
                <リンク先={route.path}>{route.path}</Link>
            </li>
        )
    })
    戻る (
        <フィールドセット>
            <legend>発見</legend>
            <h1>ただ熱いお湯を飲めばいいというわけではないことが分かりました</h1>
            <ul>
                {リンク}
            </ul>
            コアコード。ここで再度使用して、子データを通じてルートをレンダリングできます。
            <CompileRouter ルート = {ルート} />
        </フィールドセット>
    )
}
発見.meta = {
    タイトル: 「発見」、
    アイコン: ""
}
エクスポートデフォルト発見

ネストされたルートがある限り、2つのことをしなければならないことを覚えておいてください。

  • ルートの設定
  • ネストされたルートの親ルートで再度CompileRouterを使用し、ルートを渡します。

6. コンテキストが必要です

上記では集中ルーティング構成を実装しましたが、問題が見つかります。

多くのコンポーネントが導入されています。実際、プロジェクトではさらに多くのコンポーネントが導入されています。それらを1つずつ導入すると、悲惨なことになります。そこで、webpackが提供する非常に便利なAPI、require.contextを使用できます。まず、その使い方について説明しましょう。require.contextメソッドを自動的にインポートします。この方法を使用すると、面倒なコンポーネントの導入が減り、ディレクトリを深く再帰して、importではできないことを行うことができます。この方法の使い方を見てみましょう。

使用

require.context() 関数を使用して独自のコンテキストを作成できます。
この関数には 4 つのパラメータを渡すことができます。

  • 検索するディレクトリ、
  • サブディレクトリも検索するかどうかを示すフラグ。
  • ファイルに一致する正規表現。
  • mode モジュール読み込みモード、一般的な値はsync、lazy、lazy-once、eagerです
    • syncは現在のファイルに直接パッケージ化し、同期的にロードして実行します。
    • 遅延読み込みは個別のチャンクファイルを分離します
    • 一度だけ遅延ロードすると、別のチャンク ファイルが分離され、次回ロードするときにメモリ内のコードを直接読み取ることができます。
    • Eager は別のチャンク ファイルを分離するのではなく、Promise を返します。コードは、Promise が呼び出されたときにのみ実行されます。コードが最初にロードされることは理解できますが、この部分のコードの実行を遅延させることは制御できます。

webpack はビルド中にコード内の require.context() を解析します。

構文は次のとおりです。

コンテキストが必要です(
  ディレクトリ、
  (useSubdirectories = true)、
  (正規表現 = /^\.\/.*$/)、
  (モード = '同期')
);

例:

'./test' というコンテキストが必要です (false、/\.test\.js$/)。
//(作成) ファイルがテスト ディレクトリから取得され、リクエストが `.test.js` で終わるコンテキスト。
require.context('../', true, /\.stories\.js$/);
// (作成) すべてのファイルが親フォルダーとそのすべてのサブフォルダーから取得され、リクエストが `.stories.js` で終わるコンテキスト。

API

この関数には、resolve、keys、id という 3 つのプロパティがあります。

resolve は、リクエストが解決された後に取得されたモジュール ID を返す関数です。

p = require.context("...",true,"xxx") とします。
p.resolve("パス")

keys は、このコンテキスト モジュールによって処理される可能性のあるすべてのリクエストで構成される配列を返す関数でもあります (翻訳者注: 以下の 2 番目のコード スニペットのキーを参照してください)。

require.context の戻り値は関数です。関数にファイルのパスを渡すことで、モジュール コンポーネントを取得できます。

コンポーネントを require.context('../pages', true, /\.js$/, 'sync') とします。

let paths = components.keys() //インポートされたすべてのファイルのアドレスを取得します // console.log(paths)
ルートをpaths.map(path => {
    コンポーネント = components(path).default とします。
    パス = path.substr(1).replace(/\/\w+\.js$/,"")
    戻る {
        パス、
        成分
    }
})
console.log(ルート)

要約する

上記には多くの API と戻り値がありますが、説明のために 2 つだけ取り上げます。

すべてのモジュールのパスを取得し、配列を返すキーメソッド

context = require.context("../pages", true, /\.js$/); とします。

let paths = context.keys() //すべてのファイルのパスを取得する

パスの下にあるすべてのモジュールを取得します

context = require.context("../pages", true, /\.js$/); とします。

let paths = context.keys() //すべてのファイルのパスを取得します。letroutes = paths.map(path => {
    //インポートされたコンポーネントをバッチ取得します。let component = context(path).default;
    console.log(コンポーネント)
    })

これら2つをマスターして、処理を続けましょう

7. フラットデータをツリー構造に変換する(convertTreeアルゴリズム)

このアルゴリズムに私は自分で名前を付けました。まず、データをツリーに変換する必要がある理由を理解する必要があります。
予想されるルートデータは次のようになります

//目的は何ですか?
//ルーティング設定を生成する constroutes = [
     {
         パス: ""、
         コンポーネント:xxx
          子供たち:[
                 {
                     パス:"xxx"
                     コンポーネント:xxx
                 }
            ]
     }
 ]

しかし実際には、require.context処理を使用した後のデータは次のようになります

データはネストがなく完全にフラットであることがわかります。そのため、最初のステップは、このフラット データを期待どおりのツリー構造に変換することです。ステップごとに実行してみましょう。

7.1 require.context を使用してデータをフラット化する

まずは、上図のような構造に加工する必要があります。コードにはコメントもついており、難易度は高くありません。

// コンテキストが必要です()

// 1. 検索するディレクトリ、
// 2. サブディレクトリも検索するかどうかを示すフラグ。 
// 3. ファイルに一致する正規表現。
context = require.context("../pages", true, /\.js$/); とします。

let paths = context.keys() //すべてのファイルのパスを取得します letroutes = paths.map(path => {
    //インポートされたコンポーネントをバッチ取得します。let component = context(path).default;
    //メニューのレンダリングを容易にするためのコンポーネント拡張属性 let meta = component['meta'] || {}
    //console.log(パス)
    // この正規表現の目的 // アドレスは ./Discover/Djradio/index.js であるため、このタイプのアドレスは直接使用できないため、処理する必要があります //1. 次に最初の "." を削除します。結果は /Discover/Djradio/index.js になります
    //2. 処理後も、/Discover/Djradio を期待しているため、直接使用することはできません。そのため、正規表現を使用して index.js を削除します。 //3. 後続のパスがフォルダーではなく、結果が /Discover/abc.js である可能性があります。ルーティング構成のパス属性ではサフィックス名を使用できないため、.js サフィックス名は正規表現 path = path.substr(1).replace(/(\/index\.js|\.js)$/, "") で置き換えられます。
    // console.log(パス)
    戻る {
        パス、
        成分、
        メタ
    }
})

7.2 convertTreeアルゴリズムの実装

上記のデータを処理した後、フラット化されたデータをツリーデータに処理するためのメソッドをカプセル化します。アルゴリズムの時間計算量はO(n^2)です。

関数 convertTree(ルート) {
    treeArr = [] とします。
    //1. データを処理し、各データの ID と親 (一般に「お父さんはどこへ行くのか」として知られています) を処理します。
    ルート.forEach(ルート => {
        comparePaths = route.path.substr(1).split("/") とします。
        // コンソール.log(比較パス)
        比較パスの長さが1の場合
            //ルートノードであることを示します。ルートノードにはparent_idを追加する必要はありません
            ルートID = comparePaths.join("")
        } それ以外 {
            //説明には親ノードがあります//まず自身のIDを処理します
            ルートIDを比較します。
            //最後の項目がparent_idである点を除いて、comparePaths
            比較パス.pop()
            ルート.parent_id = comparePaths.join("")
        }
    })
    //2. すべてのデータが親ノードのIDを見つけたら、次は親ノードの実際の検索です。routes.forEach(route => {
        //現在のルートにparent_idがあるかどうかを判断します
        ルートの親IDが
            //親ノード //id===parent_id を持つルートは、現在のルートの親ノードです。let target =routes.find(v => v.id === route.parent_id);
            //親ノードにchildren属性があるかどうかを判断します if (!target.children) {
                ターゲット.children = []
            }
            target.children.push(ルート)
        } それ以外 {
            treeArr.push(ルート)
        }
    })

    treeArrを返す
}

上記の処理を実行すると、ツリー構造を取得できます。

次に、データをエクスポートしてアプリにインポートし、CompileRouter コンポーネントに渡す必要があります。

7.3 今後の留意事項

将来的には、ルートを自動的に処理してコンパイルするには、ページ内にファイルを作成するだけで済みます。ただし、ネストされたルートの場合は、ルート コンポーネントに CompileRouter コンポーネントを追加することを忘れないでください。主な点は次のとおりです。

  • ルーティングページを作成する
  • ネストされたルートの親ルーティングコンポーネントに追加します

8. 静的プロパティの拡張

作成した効果はありますが、メニューのレンダリングに使用すると問題が発生します。メニューをレンダリングするコンテンツがないため、コンポーネントの静的属性 meta (または other) を拡張し、自動コンパイル コードに小さな変更を加えることができます。

コンポーネント

自動化処理ロジックの完全なコード

// コンテキストが必要です()

// 1. 検索するディレクトリ、
// 2. サブディレクトリも検索するかどうかを示すフラグ。 
// 3. ファイルに一致する正規表現。
context = require.context("../pages", true, /\.js$/); とします。

let paths = context.keys() //すべてのファイルのパスを取得します。letroutes = paths.map(path => {
    //インポートされたコンポーネントをバッチ取得します。let component = context(path).default;
    //メニューのレンダリングを容易にするためのコンポーネント拡張属性 let meta = component['meta'] || {}
    //console.log(パス)
    // この正規表現の目的 // アドレスは ./Discover/Djradio/index.js であるため、このタイプのアドレスは直接使用できないため、処理する必要があります //1. 次に最初の "." を削除します。結果は /Discover/Djradio/index.js になります
    //2. 処理後も、/Discover/Djradio を期待しているため、直接使用することはできません。そのため、正規表現を使用して index.js を削除します。 //3. 後続のパスがフォルダーではなく、結果が /Discover/abc.js である可能性があります。ルーティング構成のパス属性ではサフィックス名を使用できないため、.js サフィックス名は正規表現 path = path.substr(1).replace(/(\/index\.js|\.js)$/, "") で置き換えられます。
    // console.log(パス)
    戻る {
        パス、
        成分、
        メタ
    }
})
// この種類のデータはフラット データであり、ルーティング ルールに準拠していません // 時間計算量を o(n) にできるだけ減らすアルゴリズムを実行する必要があります // 時間計算量が o(n^2) の convertTree アルゴリズムをカプセル化します
// console.log(ルート)

// id
//親ID

関数 convertTree(ルート) {
    treeArr = [] とします。
    //1. データを処理し、各データの ID と親 (一般に「お父さんはどこへ行くのか」として知られています) を処理します。
    ルート.forEach(ルート => {
        comparePaths = route.path.substr(1).split("/") とします。
        // コンソール.log(比較パス)
        比較パスの長さが1の場合
            //ルートノードであることを示します。ルートノードにはparent_idを追加する必要はありません
            ルートID = comparePaths.join("")
        } それ以外 {
            //説明には親ノードがあります//まず自身のIDを処理します
            ルートIDを比較します。
            //最後の項目がparent_idであることを除いて、comparePaths
            比較パス.pop()
            ルート.parent_id = comparePaths.join("")
        }
    })
    //2. すべてのデータが親ノードのIDを見つけたら、次は親ノードの実際の検索です。routes.forEach(route => {
        //現在のルートにparent_idがあるかどうかを判断します
        ルートの親IDが
            //親ノード //id===parent_id を持つルートは、現在のルートの親ノードです。let target =routes.find(v => v.id === route.parent_id);
            //親ノードにchildren属性があるかどうかを判断します if (!target.children) {
                ターゲット.children = []
            }
            target.children.push(ルート)
        } それ以外 {
            treeArr.push(ルート)
        }
    })

    treeArrを返す
}

エクスポートデフォルト convertTree(ルート)

// モジュールを取得する // console.log(p("./Discover/index.js").default)

//目的は何ですか?
//ルーティング設定を生成する // constroutes = [
// {
// パス: ""、
// 成分、
// 子供たち:[
// {パスコンポーネント}
// ]
// }
// ]

最後に

実は、上記の処理は、主に CompileRouter 処理の詳細度が低いため、アプリケーション レベルとしてプロジェクトで使用することはできません。次回は、プロジェクト内で認証やその他のアプリケーションに CompileRouter をどのように扱うかについて、特別に記事を書きます。

Reactでの自動ルーティングの実装に関するこの記事はこれで終わりです。Reactでの自動ルーティングの詳細については、123WORDPRESS.COMの以前の記事を検索するか、以下の関連記事を引き続き参照してください。今後とも123WORDPRESS.COMをよろしくお願いいたします。

以下もご興味があるかもしれません:
  • Reactルーティングの各バージョンのリダイレクト方法の詳細な説明
  • react-router JS 制御ルーティングジャンプの例
  • React-router v4: 履歴を使用してルートジャンプを制御する方法
  • Reactルートの遅延読み込みのためのいくつかの実装ソリューション
  • React-router4ルート監視の実装
  • React-router v4 ルーティング設定方法の概要
  • Reactルーティング認証の実装方法
  • React-Routerにルーティングページを切り替える際に遷移アニメーションを追加する方法の詳細な説明
  • React Router 4.0 以降のルーティング アプリケーションの詳細な説明
  • react-router4でルートを非同期にロードする2つの方法の詳細な説明
  • react-router-dom でのネストされたルーティングの実装

<<:  Ubuntu で FTP サーバーを構築する方法の詳細な説明 (成功保証)

>>:  MySQLエラー10061を解決する方法

推薦する

ファイルのダウンロードを実現する javascript Blob オブジェクト

目次例示する1. ブロブオブジェクト2. フロントエンド3. バックエンド要約する例示する最近、ファ...

vue+elementuiは、共有箇条書きボックスの追加と変更の完全なコードを実装します。

目次1. 新しいII. 変更element-ui は、Ele.me のフロントエンド チームが開発者...

MySQL PXC は IST 送信のみで新しいノードを構築します (推奨)

需要シナリオ: 既存の PXC 環境には大量のデータがあります。新しく購入したサーバーをこのクラスタ...

ReactとReduxの配列処理の説明

この記事では、reduce()、filter()、map()、every()、some()、spre...

Nginx サービス クイック スタート チュートリアル

目次1. Nginx の紹介1. Nginx とは何ですか? 2. Nginx を使用する理由3. ...

Linux がますます人気になっている 10 の理由

Linux はますます多くのユーザーに愛されてきました。なぜ Linux はこれほど急速に発展し、い...

Navicat PremiumでSQLファイルをインポートする方法

今日、最終プロジェクトに取り組み始めましたが、今年はMySQLデータベースを使用したため、Navic...

よく使われる3つのMySQLデータ型

MySQL のデータ フィールドのタイプを定義することは、データベースを最適化するために非常に重要で...

Nginx proxy_pass の / スラッシュによって引き起こされた殺人事件の詳細な説明

背景nginx サーバー モジュールは 2 つのサーバーにプロキシする必要があるため、異なるサーバー...

2008 年の Web デザインにおける 10 の経験

<br />インターネットは絶えず変化しており、BusinessWeek.com は専門...

非常に優れた CSS スキル 10 選のコレクションと共有

ここでは、CSS テクニックを巧みに使用することで、HTML を変更せずにブログやテンプレートの外観...

Winにmysqlをインストールする詳細な手順

この記事では、参考までにWinにmysqlをインストールする詳細な手順を紹介します。具体的な内容は次...

CSS の div の下の同じ行にある複数の要素を右揃えにする

方法1:フロート:右さらに、フローティングにするとレイアウトがよりコンパクトになります(隙間がなくな...

React は antd のアップロード コンポーネントを使用してファイル フォーム送信機能を実装します (完全なコード)

私はプロジェクトを実行するために react を使い始めたばかりで、非常に未熟で完全な初心者です。私...

CSS で実装された円形のプログレスバー

成果を達成する 実装コードhtml <div class="wrap"&g...