react-dom-router6 动态渲染路由+路由拦截

✅ 作者 : 布克吉

🍎简介 : 专注于前端开发,微信小程序,后台管理(Vue+React)

               本博客主要用于分享前端技术知识,更多内容请看下方👇

✨人生态度 :☀️Eventually everything will be fine!☀️

前言

动态渲染,顾名思义就是在数据发生改变时根据已有的逻辑自动调整,以不变应万变。

第一可以让代码面对复杂的业务需求时,更加灵活和易于维护,第二看起来也更加美观。

目录

一、动态渲染路由

1.新建routes.js文件

2.在最外层index.js中引入

3.在需要的使用的页面home.js中动态渲染

二、路由拦截

1.新建一个withGuard.js文件。

2.主页面home.js使用该拦截组件

补充:


一、动态渲染路由

router6中我们使用useRoutesOutlet来实现动态渲染路由,以下为实现方法:

1.新建routes.js文件

import { useRoutes} from 'react-router-dom';

 // 1. 准备一个路由数组 数组中定义所有的路由对应关系
const routes = [{
		path: '/',
		element: <Home/>,
		
		children:[
			{
				path: '/page//*',
				meta:{
					title:'页面一',
					role:[1,2,3]
				},
				element: <Page1/>,
				children:[
					{
						path: 'page1child1',
						meta:{
							title:'页面一子页面1',
							role:[1,2]
						},
						element: <Page1Child2/>
					},
                    {
						path: 'page1child2',
						meta:{
							title:'页面一子页面2',
							role:[1,3]
						},
						element: <Page1Child2/>
					}]
        ]
}]

//以函数形式,并在内部导出
function AppRoutes() {
    return  useRoutes(routes)
}

function RouterModel() {
    return (
        <div>
            <AppRoutes/>
        </div>
    )
}
 
export {routes,RouterModel}

2.在最外层index.js中引入

import ReactDOM from 'react-dom';
import {BrowserRouter} from "react-router-dom"
import {RouterModel} from '../Router/route.js'

ReactDOM.render(
    <BrowserRouter>	
		<RouteModel />
    </BrowserRouter>
, document.getElementById('root'));

3.在需要的使用的页面home.js中动态渲染

import {routes} from '../Router/route.js'
import React, { Component } from 'react';
import { Navigate,Outlet} from 'react-router-dom';
import {Layout, Menu} from 'antd';

const {Content} = Layout;

//用于保存动态路由的数组
let menuDom = []
class Home extends Component {
    constructor (props) {
        super(props);
        this.state = {
           
        }
    }

    componentDidMount() {
        menuDom = this.getMenuDom()
    }
	
    //根据用户角色动态生成路由菜单(根据实际情况做调整)
    getMenuDom = ()=>{
        let menuList = []
		let menuDomData = []
        //获取当前用户角色
		let role = atob(LocalStorage.getItems('currentRole'))*1
		routes.forEach(item=>{
			if(item.children){
				item.children.forEach(v=>{
					if(v.meta){
						if(v.meta.role.find(r=>role===r)!==undefined){
							if(v.children){
								let newChildren = []
								for (var i = 0; i < v.children.length; i++) {
									v.children[i].meta.role.forEach(r=>{
										if(role===r){
											newChildren.push(v.children[i])
										}
									})
								}
								v.children = newChildren
							}
							menuList.push(v)
						}
					}
				})
			}
		})
        //存入本地缓存数据
		LocalStorage.SetObjItems('menuData',menuList)
		menuList.forEach((item,index)=>{
			menuDomData.push((
				<Menu.Item key={index}>
					<Link to={item.path}>{item.meta.title}</Link>
				</Menu.Item>
			))
		})
		return menuDomData
    }

    render(){
        return(
            <Menu theme="dark">
				{menuDom}
            </Menu>

            {/* 渲染对应的页面*/}
            <Content style={{ padding: '4px 15px',backgroundColor:'#fff' }}>
                <Outlet />
            </Content>
        )
    }

}

其中Oulet会自动渲染路由对用的页面,这里是useRoutes起到的作用

二、路由拦截

在上述动态渲染路由时,提到了用户角色,我们会根据用户角色的权限,来动态判断,具体页面中的子路由。

但是有一个问题,我们只是根据用户的角色来动态生成菜单数组进行渲染,如果直接在地址栏输入页面的地址,仍然会进行跳转,为此,提供了一个方法来拦截非法路由并跳转到404页面

这里用到了reouter6中的useLocation,来获取当前页面的路由

1.新建一个withGuard.js文件。

import { useEffect } from "react";
import { useDispatch, useSelector } from "react-redux";
import { Navigate, useLocation } from "react-router-dom";
import LocalStorage from '../Common/Common.js'

function Guard({ Cmp, ...props }) {
    console.log('Cmp', Cmp, props);
	const { pathname } = useLocation();
    /* const { user } = useSelector(state => state);
    const dispatch = useDispatch();
    useEffect(() => {
        // 若没有用户信息,保存现在的地址
        if (!user) {
            dispatch({
                type: 'prevPath',
                prevPath: pathname
            })
           
        }
    }, [user]) */
    // 若有用户信息正常展示组件,若没有跳转到登录页
	console.log(pathname);
    LocalStorage.SetItems('pathname',pathname)
	//根据需求处理获取到的当前的路由信息
	let pathnameArr = pathname.split('/').filter(path=>path!==''&&path!=='*')
	console.log(pathnameArr);
	let path = pathnameArr[pathnameArr.length-1]
	console.log(path);

    //函数用于验证当前路由是否合法,否则返回false,并跳转到404页面
	function validPath(){
		let flag = false
		
		let menuData  =	[]
        //此处获取home页面存入本地的缓存数据(菜单数组)
		menuData = LocalStorage.getObjItems('menuData')
		console.log(menuData);
		let regex = new RegExp(path);
		for (var i = 0; i < menuData.length; i++) {
			if(regex.test(menuData[i].path)){
				flag = true
				break;
			}else if(menuData[i].children){
				menuData[i].children.some(v=>{
					if(regex.test(v.path)){
						flag = true
						return true
					}
				})
			}
		}
		console.log(flag);
		return flag
	}
	let _token= LocalStorage.getItems('_t')
	// 获取路由与menu 的path 匹配
    return _token?  (validPath()? <Cmp {...props} />:<Navigate to="/404" />):<Navigate to="/login" />
}

// 一个高阶函数,将组件和props都传递给函数组件Guard
export default function withGuard(Cmp) {
    return (props) => <Guard Cmp={Cmp} {...props} />
}

2.主页面home.js使用该拦截组件

import WithGuard from '../Router/WithGuard.js'

/*

此处省略500行

*/

//页面导出时
export default WithGuard(Home);

由此可实现动态路由渲染和拦截🚀🚀🚀

补充:

1.代码中使用的LocalStorage为简单的自行封装使用

2.关于404页面,这里简单渲染一下,页面中倒计时五秒后便返回原来页面

import React, { Component } from 'react';
import withRouter from "../Router/widthRouter";
import {Empty } from 'antd';
import LocalStorage from '../Common/Common.js'
let timer = null
class Page404 extends Component {
    constructor(props){
        super(props);
        this.state = {
          time:5
        }
    }
	componentDidMount(){
		let lastPath = LocalStorage.getItems('pathname')
		let num
		if(lastPath){
			timer = setInterval(()=>{
				num = this.state.time
				num = num - 1
				this.setState({
					time:num
				},()=>{
					if(this.state.time===0){
						this.props.navigate(lastPath)
					}
				})
				
			},1000)
		}
	}
	componentWillUnmount(){
		clearInterval(timer)
	}
	render(){
		return(
		 <Empty
		  imageStyle={{ marginTop: 300 }}
		    description={
		      <span>
				该页面不存在或无权限访问, <span style={{fontSize:'18px',color:'#f00'}}>{this.state.time}</span> 秒后,返回上一个页面
		      </span>
		    }
		  >
		  </Empty>
		)
	}
}
export default withRouter(Page404)

网上也有其他文章介绍了相关知识。还封装成了组件,研究了许久发现不会用,大家可以参考下。

react-router v6 路由统一管理及路由拦截方案_react.js_醉逍遥neo-华为云开发者联盟上一篇分享了react-router v5 版本的路由管理及拦截方案,但也存在一些缺陷,例如不支持嵌套路由、不支持动态路由参数等。后来看到了react-router v6 版本useRoutes api 的特性,决定升级到v6版本,并对路由管理和路由拦截的实现方案进行了重构。v6版本目前网上的文章寥寥无几,实现过程基本靠自己摸索,下面分享具体方案。一、react-router v6官方文档:htt 醉逍遥neo 华为云开发者联盟icon-default.png?t=N7T8https://huaweicloud.youkuaiyun.com/638f1232dacf622b8df8e82c.html

以上就是本文所有内容了,如果觉得可以,欢迎点赞、收藏+关注!

### 如何在 React Router v6 中获取路由传递的参数 在 React Router v6 中,为了处理异步操作和 API 调用,虽然框架本身不强制使用特定库,但可以借鉴 Angular 使用 RxJS 处理类似场景的方式[^1]。不过,在具体实现上,React Router 提供了自己的机制来管理路由及其参数。 当定义带有动态部分路径时,这些动态片段可以通过 `useParams` 钩子轻松访问。此钩子返回一个对象,其中包含当前 URL 的所有匹配参数: ```javascript import { useParams } from 'react-router-dom'; function MyComponent() { let params = useParams(); console.log(params); // 打印出的对象包含了所有的URL参数 return ( <div> {/* 组件内部逻辑 */} </div> ); } ``` 对于更复杂的查询字符串解析需求,则推荐利用 `useSearchParams` 来代替传统的手动解码方式。这使得开发者能够更加方便地读取并响应于地址栏中的键值对变化: ```javascript import { useSearchParams } from 'react-router-dom'; function SearchExample() { const [searchParams, setSearchParams] = useSearchParams(); function handleChange(event) { const name = event.target.name; const value = event.target.value; setSearchParams({ ...Object.fromEntries(searchParams), [name]: value, }); } return /* JSX */; } ``` 值得注意的是,上述方法适用于不同类型的路由配置方案——无论是静态声明还是通过编程方式进行导航后的结果页面都能正常工作。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值