1. ホーム
  2. ジャバスクリプト

react-routerのルートブロッカー(ナビゲーションガード)を実装する方法

2022-02-09 23:06:37

react-routerのルートインターセプトを自分で実装する前に、vueのルートインターセプトがどのように使われ、何をするのかを見てみましょう。

その名の通り ビューアルーター は、主にジャンプやキャンセルによるナビゲーションをガードするために使用されるナビゲーションガードを提供します。

グローバルガード

を使用することができます。 ルーター.beforeEach を使用して、グローバルな先行者ガードを登録します。

const router = new VueRouter({ ... })

router.beforeEach((to, from, next) => {
  // ...
Copy the code

ナビゲーションがトリガーされると、グローバルな先行ガードが作成された順に呼び出されます。ガードはパースによって非同期に実行され、その時点でナビゲーションはすべてのガードに実行されます。 解決 はすべてのガードが終了するまで待機する。

ここで、vueはすべてのルートジャンプの前にbeforeEachでリスニングし、ルールにマッチすればジャンプし、そうでなければ指定した場所にジャンプすることがわかります。

react-routerで同じapiが提供されないのはなぜですか?に対して、作者はgithubで回答しています。

You can do this from within your render function. JSX doesn't need an API for this because it's more flexible.
Copy the code

おそらく、これが意味するところは

You can perform this operation in the rendering function. JSX does not require an API because it is more flexible.
Copy the code

リンク react-routerのルートインターセプトに関する公式説明書

作者の回答にあるように、彼はreact-routerを柔軟なものにしたいので、あまり多くのapiを追加したくはないようです。これらのapiは、ユーザーがニーズに応じて独自のルートインターセプトを実装できるようにするためのものです。ここでは、ほとんどのニーズを満たすルートインターセプターを実装する方法を説明します。

react-routerのバージョン。4.0

まず、react-router-configを使って、ルートの設定を配列の形で書きます。

//routerConfig.js
const routes = [
    {
        path: '/',
        component: 'component/app',
        routes: [
            {
                path: '/asd',
                component: 'component/topics',
                routes: [
                    {
                        path: '/asd/login',
                        component: 'component/home'
                    }
                ]
            }
        ]
    }
]

export default routes
Copy the code

コンフィギュレーションで書かれているのは、プロジェクト全体のルーティング構成を見て、どこにジャンプするのか、どのコンポーネントがどの位置の下に表示されるのかを正確に把握することが直感的にできるからです。

見ていただければわかると思いますが、この中でドキュメントと違うことを書いたのは2箇所です。

1. I have only one list item in the whole array, just this one object.

2. The value of my compoent is a string, not an object or method
Copy the code

最初のポイント:我々は現在のページでルートルートが必要な場合がありますので、ルートルートで、我々はおそらくテーマの色の設定、グローバルコンテンツの表示などで何かをしたい、ここで、我々はそれを行うことができます、残りのすべて、彼の中で ルート でOKです。

2点目。これを行う目的は、ルートの高速レンダリングを可能にすることであり、通常の使用では一般的に次のように行います。

//pseudo-code, for reference only
import A from '. /a'
{
    path:'/',
    component:A
}
Copy the code

基本的に、これはどのように実装されている、問題がある場合、私たちのページには、20、あるいは50、100のパスをジャンプするには、どのように、そのたびに我々は、ルータ.jsファイルに読み込むように、それは非常に多くのファイルをインポートする必要がある、これは非常にコードの実行効率とページの描画速度に影響を与えることである。

以下、レンダリング方法について詳しく説明します。

ルートは全体として配列なので、ここでループを通過することになりますが、もしこれを最も不格好な方法で行えば

<Route path='/' component={a} />
<Route path='/b' component={b} />
<Route path='/c' component={c} />
<Route path='/d' component={d} />
...
Copy code

もちろん、この方法でルートジャンプを実装するのは賢明ではありません。メンテナンスしやすく、読みやすいルートを書きたいのです。

そこで、ここではルートの配列を繰り返し処理するメソッドを書きました。

//renderRoutesMap.js
import RouterGuard from '. /routerGuard'
const renderRoutesMap = (routes) => (
    routes.map((route, index) => {
        return (
            <Route key={index} path={route.path} render={props => (
                <RouterGuard {... .route} {. .props} />
            )}
            />
        )
    })
)

export default renderRoutesMap
Copy the code

ここでルートのレンダリングを少しトラバースして、ルートオブジェクトを取って一度だけ通過します、ここでキッカーが登場します!

RouterGuardは、私たちの焦点です。ここでは、実際のルートブロック(ナビゲーションガード)を行うつもりです!

//routerGuard.js
import React, { Component } from 'react'
import { withRouter } from 'react-router-dom'
import Loadable from 'react-loadable'
import { connect } from 'react-redux'
import renderRoutesMap from '. /renderRoutesMap'

const mapStateToProps = state => (state)
const mapDispatchToProps = dispatch => ({ . .dispatch })

class RouterGuard extends Component {
    constructor(props) {
        super()
    }
    componentWillMount() {
        let { history: { replace }, authorization, location } = this.props
        if (authorization) replace('. /login')
        if (location.pathname === '/') replace('. /asd')
        console.log('Interception before route jump', this.props)
    }
    render() {
        let { component, routes = [] } = this.props
        console.log('ready to render before compoent', this.props)
        const LoadableComponent = Loadable({
            loader: () => import(`. /${component}`),
            loading: () => (
                
11111

            )
        })
        return (
            
{renderRoutesMap(routes)}
) } } export default withRouter(connect(mapStateToProps, mapDispatchToProps)(RouterGuard)) Copy the code
//renderRoutes.js import renderRoutesMap from '. /renderRoutesMap' /** * renderRoutes render routes * @param {array} routes route list * @param {object} extraProps = {} properties of extra * @param {object} switchProps = {} the properties of switch */ const renderRoutes = ({ routes, extraProps = {}, switchProps = {} }) => ( {renderRoutesMap(routes)} ) export default renderRoutes //index.js const router = () => ( renderRoutes({ routes: routerConfig }) ) export default router Copy the code

ここでは、実際に私のプロジェクトで使われているコードなので、react-reduxが入っているので、reduxを使っていない場合は分解してください。

componentWillMountはreactコンポーネントのライフサイクルで、レンダリング前に呼び出され、reduxからの引数と、ルートから持ってきた引数を取得することができます。

ここでは、authorizationを使っているので、authorizationがtrueの場合、ログインしていないことを意味し、ログインページにジャンプしています。

また、ルートルートにいるときに、別のアドレスにジャンプするようにリダイレクトも行っています。

これで実は真のルート遮断ができるのですが、それだけでは不十分で、できるだけ高速にレンダリングし、ユーザー体験を向上させるためには、遮断にプラスして行わなければならないのです。

ここでは ローダブル プラグインを使用します。これは、動的にインポートされたコンポーネントで上位のコンポーネントをロードし、ユーザーエクスペリエンスを向上させるために使用します。

importは変数をサポートしないので、ここではテンプレートストリングのアプローチを使っています。コンポーネントを入力してレンダリングの準備をするたびにインポートするだけなので、レンダリングのたびにリソースを浪費する必要がなく、最初のレンダリングを確実に速くすることができます。

最後に、ルート設定、ルート配列のレンダリング、ルートコンポーネントのレンダリングをつなぎ合わせて、react-router全体のルートインターセプト(ナビゲーションガード)とします。


<ルーター

<スイッチ


            {renderRoutesMap(routes)}となります。
        




最後に、ページ内で、index.jsを導入すれば完了です。

私が勉強や仕事で使っている方法なので、間違っているところがあればご指摘いただければと思います。最後に、いいね!やフォローをいただけると嬉しいです、ありがとうございます。