携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第14天,点击查看活动详情
1.react-router-6安装与配置
react-router-6的推出让react伙伴们是爱恨交加啊,大家不禁沉思他娘又出一个版本,刚学会一个版本就推出下一个版本,不过大家不必有淡淡的忧伤,这次更新是对react-router的瘦身,去除了许多react-router5臃肿和复杂的路由机制。因此它实际让我们学习更快,上手更容易,并且了解vue的伙伴们会发现react-router6已经和vue的路由基本趋于一致了。是不是很意外,废话不多说上车。
安装
npm install react-router-dom@6
简单配置
index.js
import React from 'react';
import App from './App';
//1.选择路由模式
import { BrowserRouter,HashRouter } from "react-router-dom";
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
//2.组件包裹
<BrowserRouter>
<App />
</BrowserRouter>
);
App.js
import { Routes,Route } from "react-router-dom";
import Home from "./views/Home"
import Header from "./views/Header"
import Main from "./views/Main"
import Footer from "./views/Footer"
function App() {
return (
<Routes>
<Route path="/" element={<Home></Home>}></Route>
<Route path="/header" element={<Header></Header>}></Route>
<Route path="/main" element={<Main></Main>}></Route>
<Route path="/footer" element={<Footer></Footer>}></Route>
</Routes>
);
}
export default App;
效果展示
2. 路由跳转方式
1. Link组件
使用方式: to表示传递的路由地址
<Link to='/index'></Link>
示例
Home.js
import { NavLink,Link } from "react-router-dom"
export default function Home() {
return <div>
<div><Link to='/header'>header</NavLink></div>
<div><Link to='/main'>main</Link></div>
<div><Link to='/footer'>footer</Link></div>
</div>
}
Header.js
import { Link } from "react-router-dom"
export default function Header() {
return <div>
header
<Link to='/'>返回首页</Link>
</div>
}
效果展示
2. NavLink组件
NavLink组件和Link组件都是用于路由跳转的。可能有人疑惑为什么功能一样还要出个NavLink? 其实NavLink还有一个逆天属性,我个人感觉十分好用。它可以携带激活属性,它可以判断是否当前路由和自己需要跳转的路由一致性,据此我们可以设置激活后的路由样式。
使用
style属性传递是一个回调函数,回调函数的参数记录了当前页面路由和NavLink指向的路由是否是一个,如果是一个则e.isActive返回true。
<NavLink to='/' style={(e)=>{console.log(e.isActive)}}>
需求
注意看下面图片的tarbar。我们需要根据选择的tarbar跳转对应的路由,然后激活路由选中的样式。 如果用NavLink是十分十分十分简单的。
设计思路
将tarbar抽离成一个组件,使用NavLink自带样式激活特性完成。需要显示tabar的页面直接导入tarbar组件就可以。
App.js:全局路由定义
import { Routes,Route } from "react-router-dom";
import Home from "./views/Home"
import Header from "./views/Header"
import Footer from "./views/Footer"
function App() {
return (
<Routes>
<Route path="/" element={<Home></Home>}></Route>
<Route path="/header" element={<Header></Header>}></Route>
<Route path="/footer" element={<Footer></Footer>}></Route>
</Routes>
);
}
export default App;
Nav.js: 负责tarbar组件切换
import { NavLink } from "react-router-dom";
import "./style.css"
export default function Nav() {
return (
<div className="nav">
<NavLink to='/' style={({ isActive }) => { return isActive ? { color: "red" } : null }}>首页</NavLink>
<NavLink to='/header' style={({ isActive }) => { return isActive ? { color: "red" } : null }}>头部</NavLink>
<NavLink to='/footer' style={({isActive})=>{return isActive?{color:"red"}:null}}>尾部</NavLink>
</div>
)
}
Home.js:home页面
import Nav from "./Nav"
export default function Home() {
return <div>
home
<Nav/>
</div>
}
Header.js:header页面
import Nav from "./Nav"
export default function Header() {
return <div>
header
<Nav/>
</div>
}
Footer.js:footer页面
import Nav from "./Nav"
export default function Footer() {
return <div>
footer
<Nav/>
</div>
}
效果展示
是不是十分十分十分的简单和方便,我们无需使用js和css去判断是否路由显示,而且当页面手动触发到某个路由时,tarbar也会自己处理激活。
3.useNavigate方法
上面两个是通过组件完成的路由切换和跳转,下面介绍的useNavigate是通过js完成路由跳转
使用
import { useNavigate } from "react-router-dom"
const nav = useNavigate()
nav("index")//跳转到index路由
nav(1)//前进
nav(-1)//后退
Home.js
import { useNavigate } from "react-router-dom"
export default function Home() {
const nav = useNavigate()
//跳转到header页面
const goHeader = () => {
nav("header")
}
return <div>
home
<div onClick={goHeader}>跳转到header</div>
</div>
}
Header.js
import { useNavigate } from "react-router-dom"
export default function Header() {
const nav = useNavigate()
//返回上一层
const goBack = () => {
nav(-1)
}
return <div>
header
<div onClick={goBack}>返回上一页</div>
</div>
}
页面展示
3.路由参数
路由中我们可以传递动态参数,通常路由的动态参数主要有两类
//第一类
localhost:3000/page/1
//第二类
localhost:3000/page=1
路由参数一:useParams
/page/1
对于上面的动态路由参数,我们可以使用useParams获取动态的参数
import { useParams } from "react-router-dom"
const params = useParams()
console.log(params)
App.js
import { Routes,Route } from "react-router-dom";
import Home from "./views/Home"
import Header from "./views/Header"
import Footer from "./views/Footer"
function App() {
return (
<Routes>
<Route path="/header/:id" element={<Header></Header>}></Route>
</Routes>
);
}
export default App;
Header.js
import { useParams } from "react-router-dom"
export default function Header() {
const params = useParams()
console.log(params.id)
return <div>
header
</div>
}
页面效果
路由参数二:useSearchParams
/page?name=dzp&age=22
对于这种路由参数的设置和获取我们可以通过useSearchParams来实现
使用
import { useSearchParams } from "react-router-dom"
const [params, setParams] = useSearchParams()
//获取参数
console.log(params.get('传递的key')
//设置参数
setParams({
key1:value1
key2:value2
})
Footer.js
import { useSearchParams } from "react-router-dom"
export default function Footer() {
//第一个参数获取路由参数,第二个参数用于设置路由参数
const [params, setParams] = useSearchParams()
console.log(params.get('name'),params.get('age'))
const setObj = () => {
//设置路由参数
setParams({
name: "mingming",
age:100
})
}
return <div>
footer
<div onClick={setObj}>设置参数</div>
</div>
}
页面效果
4.路由其他信息(pathname,url,search等)
useLocation
useLocation可以获取当前路由的许多配置信息,常用的如下
-
pathname:路由配置项对应的path(十分常用)
-
search:(url搜索)
-
hash
//127.0.0.1:3000/login?name=dzp import { memo,useState,useContext } from "react"; import { useLocation } from "react-router-dom"; const Login: React.FC = () => { const location = useLocation(); console.log(location.pathname);///login return ( <div className={styles.input}> login </div> ) }
export default memo(Login);
5.嵌套路由:Outlet
嵌套路由的设计和vue一模一样,就是换了个组件名称而已。使用Outlet来放置嵌套子路由的位置
嵌套路由定义和使用
直接在需要嵌套的路由route内部继续写子路由就可以
App.js:路由定义
import { Routes,Route } from "react-router-dom";
import Home from "./views/Home"
import Child1 from "./views/Child1"
import Child2 from "./views/Child2"
function App() {
return (
<Routes>
<Route path="father" element={<Home></Home>}>
<Route path="child1" element={<Child1 />}></Route>
<Route path="child2" element={<Child2/>}></Route>
</Route>
</Routes>
);
}
export default App;
Home.js
使用Outlet作为占位符给子组件提供位置
import { Outlet } from "react-router-dom";
export default function Child1() {
return <div>
home
<Outlet/>
</div>
}
Child1.js
export default function Child1() {
return <div>child1</div>
}
Child2.js
export default function Child2() {
return <div>child2</div>
}
页面效果
6.路由统一管理与懒加载
router6版本的路由统一管理是十分十分便捷的,不同于router5需要安装单独的配置路由依赖,router6可以直接将所有的路由进行集中式管理。
6.1 第一种:useRouter管理
1. 新建router/index.js
import Home from "./../views/Home"
import Page1 from "../views/Page1"
import Page2 from "../views/Page2"
import Son from "../views/Son"
export default [
{
path:"/",
element:<Home/>,
children:[
{
path:"son",
element:<Son/>
}
]
},
{
path:"/page1",
element:<Page1/>
},
{
path:"/page2",
element:<Page2/>
}
]
2. app.js
直接使用useRoutes导出路由项
import router from "./router/index"
import {useRoutes} from "react-router-dom"
function App() {
return useRoutes(router)
}
export default App;
3.页面效果
4. 页面懒加载配置
当我们首次进入页面时,默认会加载所有的路由,因此会加剧首页的负担,可能存在首页白屏问题。基于此,我们往往需要对部分组件采取懒加载的方式实现性能优化。
改造后的路由配置
导入Suspense,lazy完成路由的懒加载配置
import { Suspense,lazy } from "react"
const Home = lazy(()=>import("./../views/Home"))
const Page1 = lazy(()=>import("./../views/Page1"))
const Page2 = lazy(()=>import("./../views/Page2"))
const Son = lazy(()=>import("./../views/Son"))
//懒加载配置处理
const lazyLoad = e => {
return <Suspense fallback={<div>loading...</div>}>{e}</Suspense>
}
export default [
{
path:"/",
element:lazyLoad(<Home/>),
children:[
{
path:"son",
element:lazyLoad(<Son/>)
}
]
},
{
path:"/page1",
element:lazyLoad(<Page1/>)
},
{
path:"/page2",
element:lazyLoad(<Page2/>)
}
]
6.2 Router与Route管理
route/index.js
import Home from "./../views/Home"
import Page1 from "../views/Page1"
import Page2 from "../views/Page2"
import Son from "../views/Son"
export default [
{
path:"/",
element:<Home/>,
children:[
{
path:"son",
element:<Son/>
}
]
},
{
path:"/page1",
element:<Page1/>
},
{
path:"/page2",
element:<Page2/>
}
]
App.js
遍历router数组生成Router和Route组件
import routes from "./route/index.js"
export default function App(){
return (
<Routes>
{ routes.map(item=>
<Route path={item.path} element={item.element}>
{item.children && item.children.map(itm=>(
<Route path={itm.path} element={itm.element}></Route>
))}
</Route>
)}
</Routes>
)
}
6.3 RouterProvider方式
index.js入口文件
import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App";
import "./index.css";
const root = ReactDOM.createRoot(
document.getElementById("root") as HTMLElement
);
root.render(
<App />
);
App.js
import React from 'react';
import { RouterProvider } from 'react-router-dom';
import routes from "./router"
function App() {
return (
<RouterProvider router={routes}></RouterProvider>
)
}
export default App;
router/index.js
import React, { ReactElement, createElement } from "react";
import Page1 from "./../views/Page1";
import Page2 from "./../views/Page2";
import Login from "./../views/Login";
import NotFound from "./../views/404";
import Son1 from "./../views/Son1";
import BeforeEnter from "./BeforeEnter";
import { createBrowserRouter } from "react-router-dom";
export const routes = [
{
path: "/",
element: Page1,
meta:{
isCheck:true
},
children: [
{
path: "/son1",
element: Son1,
meta:{
isCheck:true
},
},
],
},
{
path: "/page2",
element: Page2,
meta: {
isCheck:true
},
},
{
path: "/login",
element:Login,
},
{
path: "*",
element: NotFound,
},
];
export default createBrowserRouter(routes);
总结
以上我对React router 6的总结,希望伙伴们动动小手点个赞,谢谢。