Как реализовать перехватчик маршрута react-router (navigation guard)

React.js

Прежде чем мы реализуем перехват маршрута react-router, давайте посмотрим, как используется перехват маршрута vue и что он сделал:

Как его имя,vue-routerПредусмотренные навигационные охранники в основном используются для защиты навигации путем прыжка или отмены.

глобальная гвардия

вы можете использоватьrouter.beforeEachЗарегистрируйте глобальную защиту вперед:

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

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

Когда срабатывает навигация, глобальные передние охранники вызываются в том порядке, в котором они были созданы. Guard выполняется асинхронно, и в это время выполняется навигация во всех Guards.resolveОжидание завершения.

Здесь мы видим, что vue может отслеживать все переходы маршрутизации в beforeEach перед всеми переходами маршрутизации. Если он соответствует правилам, он будет переходить. Если он не соответствует правилам, он перейдет в указанное мной местоположение.

Почему в реактивном маршрутизаторе нельзя предоставить тот же API? Автор ответил на гитхабе:

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

Вероятно, это означает:

您可以在渲染功能中执行此操作。JSX不需要API,因为它更灵活。

Связь:официальное описание перехвата маршрута react-router

Как видно из ответа автора, он надеется, что react-router гибкий и не хочет добавлять в него слишком много API, которые должны позволять пользователям реализовывать собственный перехват маршрутизации в соответствии со своими потребностями. Затем начните реализовывать перехват маршрута, который может удовлетворить большинство ваших потребностей.

версия реактивного маршрутизатора: 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

Он написан в виде конфигурации, потому что очень интуитивно понятно, что конфигурация маршрутизации всего нашего проекта знает, куда мы хотим перейти, и какие компоненты будут отображаться в каком месте.

Следует заметить, что два места, которые я написал здесь, отличаются от документации:

1.我整个数组只有一个列表项,只有这个一个对象。

2.我的compoent的值是字符串,而不是一个对象或者方法

Первый пункт: Потому что нам может понадобиться корневой маршрут на текущей странице.В корневом маршруте мы можем делать некоторые операции, похожие на настройку цвета темы и отображение глобального контента.Вот, мы можем сделать это, остальное егоroutesЭто нормально делать внутри.

Второй момент: цель этого - добиться более быстрого рендеринга маршрутизации.При обычном использовании мы обычно делаем это:

//伪代码,仅供参考
import A from './a'
{
    path:'/',
    component:A
}

В основном это реализовано так.Есть проблема с этой реализацией.Если у нашей страницы 20 братьев,а то и 50 или 100 путей для перехода,что нам делать,чтобы мы каждый раз подгружали файл router.js. раз необходимо импортировать такое количество файлов, что сильно влияет на эффективность выполнения кода и скорость рендеринга страницы.

Конкретно как рендерить, мы будем подразделять по порядку ниже.

Так как весь маршрут представляет собой массив (массив), то здесь придется делать цикл, если мы реализуем его самым громоздким способом

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

Очевидно, что неразумно реализовывать переход по маршруту таким образом, мы хотим написать поддерживаемый и легко читаемый маршрут.

Итак, здесь я написал метод для перебора массива маршрутов.

//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

这里我们把路由的渲染做了一个小小的遍历,把我们的路由对象,去做了一次遍历,重点来了! ! !

Наша цель — 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('路由跳转前的拦截', this.props)
    }
    render() {
        let { component, routes = [] } = this.props
        console.log('准备渲染compoent前', this.props)
        const LoadableComponent = Loadable({
            loader: () => import(`../${component}`),
            loading: () => (
                <span>11111</span>
            )
        })
        return (
            <div>
                <LoadableComponent {...this.props} />
                {renderRoutesMap(routes)}
            </div>

        )
    }
}

export default withRouter(connect(mapStateToProps, mapDispatchToProps)(RouterGuard))

Здесь, собственно, код, используемый в моем проекте, поэтому в нем будет react-redux, если вы не используете redux, то можете дизассемблировать его самостоятельно.

componentWillMount — это жизненный цикл компонентов реакции, он вызывается перед рендерингом, здесь мы можем получить параметры в редуксе, а также можем получить параметры, принесенные маршрутизацией.

Здесь я использую авторизацию.Если моя авторизация верна, это означает, что я не вошел в систему и перехожу на страницу входа в систему.

Я также сделал операцию перенаправления, например, когда используется корневой маршрут, я хочу перенаправить на другой адрес.

На самом деле этим можно добиться реального перехвата роутинга, но этого недостаточно, мы не только делаем перехват, нам также нужно делать is, помимо перехвата, но и максимально ускорить скорость рендеринга, улучшить пользователя опыт.

Вот, я использую его одинLoadableПлагин используется для загрузки компонентов более высокого порядка с динамически импортированными компонентами для улучшения взаимодействия с пользователем.

Здесь я использую только импорт, а improt не поддерживает переменные, поэтому здесь я использую метод строки шаблона Каждый раз, когда я ввожу компонент и готовлюсь к рендерингу, я импортирую компонент, чтобы его можно было использовать при каждом рендеринге, вам не нужно тратить ресурсы впустую, и вы также можете сделать так, чтобы скорость первого рендеринга была выше.

Наконец, мы соединили конфигурацию роутинга, рендеринг массива роутинга и рендеринг компонентов роутинга, весь перехват роутинга react-router (navigation guard)

//renderRoutes.js
import renderRoutesMap from './renderRoutesMap'
/**
 * renderRoutes 渲染路由
 * @param  {array}      routes              路由列表
 * @param  {object}     extraProps  = {}    extra的属性
 * @param  {object}     switchProps = {}    switch的属性
 */
const renderRoutes = ({ routes, extraProps = {}, switchProps = {} }) => (
    <Router>
        <Switch {...switchProps}>
            {renderRoutesMap(routes)}
        </Switch>
    </Router>
)

export default renderRoutes

//index.js
const router = () => (
    renderRoutes({
        routes: routerConfig
    })
)
export default router

Наконец, на странице вы можете импортировать index.js.

Именно так я использую в своей учебе и работе.Если что-то не так, я надеюсь, вы можете указать на это. Наконец, я надеюсь, что вам всем понравится и вы уделите больше внимания, спасибо 🙏