React Router v4 & v5 拦截器(钩子)、静态路由、route-view 实现

本文介绍了如何在React Router v4 和 v5 中实现拦截器(钩子函数)、静态路由配置以及类似`route-view`的功能。通过自定义组件和静态路由表,结合官方文档和社区方案,实现了路由权限管理和多层级路由的便捷管理。
摘要由CSDN通过智能技术生成

前提

React Routerv3 版本之前 是有 onEnter 钩子函数的,也支持静态路由配置;,但到了 v4 版本后钩子函数被移除,官方说是为了将此提供给开发者,由开发者自由发挥。既然如此我们就只能自己实现,目前网上有很多版本,大多都是差不多的,这里做一个总结并深化一下。同时提供钩子函数或者vue中叫路由守卫和静态化路由配置。

钩子函数实现

钩子函数实现比较简单,只需要包装一下官方的路由即可实现,这里我们允许钩子支持 Promise 异步,就需要一个异步组件;代码如下

异步组件代码

class AsyncBeforeEnter extends React.PureComponent {
    constructor(props) {
        super(props)
        this.state = {
            // 注意:此处component和render不会同时使用,同Route中component和render,render方法优先级要高
            // 目标组件 同 <Route componet>
            Component: null,
            // 目标组件render 方法  同 <Route render>
            render: null,
            // 错误信息
            error: null,
            // 标记异步是否完成
            completed: false
        }
    }
    componentDidMount() {
        const { beforeEnter, ...props } = this.props
        // beforeEnter 钩子函数
        const enter = beforeEnter({ ...props })
        if (isPromise(enter)) {
            // 判断是否是Promise
            enter
                .then(next => {
                    this.handleAfterEnter(next)
                })
                .catch(error => {
                    console.error(error)
                    this.setState({ error })
                })
        } else {
            this.handleAfterEnter(enter)
        }
    }
    handleAfterEnter(next) {
        // 结果处理
        const { route = {}, ...props } = this.props
        // 如果结果是null 或者undefined 或者 true : 不做任何处理直接渲染组件
        if (next === null || next === undefined || next === true) {
            this.completed(route.component, route.render)
            return
        }
        // 返回false:阻止组件的渲染
        if (next === false) {
            this.completed(null)
            return
        }

        // 返回 string : 跳转的路由,类似http中302状态码
        // 这里使用 React Router 的 Redirect 做跳转
        if (typeof next === 'string') {
            this.completed(null, () => <Redirect to={next} from={props.location.pathname} />)
            return
        }
        // 返回React 组件
        if (typeof next === 'function' || React.isValidElement(next)) {
            this.completed(null, () => next)
            return
        }

        // 返回 Object: 如果有 redirect=true 的属性,做跳转
        // 否则使用 Route 组件渲染
        if (isPlainObject(next)) {
            const { redirect, ...nextProps } = next
            if (redirect === true) {
                this.completed(null, () => <Redirect {...nextProps} {...{ from: props.location.pathname }} />)
                return
            }
            this.completed(() => <Route {...nextProps} />)
            return
        }
        warn(`"${props.location.pathname} => beforeEnter"
hook return values error. expected null? undefined? true? React.Component? HTMLElement? Route props?
route props detail to see
https://reacttraining.com/react-router/web/api/Route
https://reacttraining.com/react-router/web/api/Redirect`
        )
        // 例外情况 阻止组件的渲染
        this.completed(null)
    }
    /**
     * 完成后改变state渲染组件:
     * @param component 
     * @param render 
     */
    completed(component, render) {
        this.setState({ Component: component, render, completed: true, error: null })
    }

    getExtraProps() {
        // 去掉钩子函数,获取其他props
        const { loading: Loading, beforeEnter, ...props } = this.props
        return { ...props }
    }
    render() {
        const { Component, render, error, completed } = this.state
        if (!completed) {
            // 未完成
            return null
        }
        // 已完成
        if (render && typeof render === 'function') {
            return render(this.getExtraProps())
        }
      
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值