前言
前端路由的作用就是将单页应用的状态处理成多页路由的样子,react 和 vue 的路由是一样的,一个地址对应一个组件,下面看看 react-router
的用法
安装
在 vue 中想要使用 router
需要进行安装,react 一样也需要安装
目前 react-router
全称为 react-router-dom
,当前最新版是 6
安装指令如下
npm i react-router-dom@6
Link
接下来实现一个效果,点击首页展示首页这个页面内容,点击关于页展示关于这个页面内容
import React from 'react';
import { BrowserRouter, Link, Routes, Route } from 'react-router-dom'
const Home = () => <div>this is home</div>
const About = () => <div>this is about</div>
const App = () => {
return (
<div className='app'>
<BrowserRouter>
<Link to='/'>首页 | </Link>
<Link to='about'>关于</Link>
<Routes>
<Route path='/' element={<Home />}></Route>
<Route path='/about' element={<About />}></Route>
</Routes>
</BrowserRouter>
</div>
);
};
export default App;
直接在根组件中写两个页面出来,路由的写法需要用 BrowserRouter
进行包裹,这其实就是 history
模式的路由,哈西模式的路由是 HashRouter
,另外你需要引入 Link
,这其实就是 a
标签。 react 中的路由入口是 Routes
,里面去写单个的路由,单个路由需要写 path
和 element
这是用 a
标签去跳转页面,还有个方法是用 button
来跳转页面
Button
vue 中想要在组件中跳路由需要引入 useRouter
,拿 router
去 push
跳转
而 react 则是引入一个 hooks
,useNavigate
,调用这个 hooks
就可以得到一个跳转路由的方法
import React from 'react';
import { BrowserRouter, Link, Routes, Route, useNavigate } from 'react-router-dom'
const Home = () => {
const navigate = useNavigate()
return (
<div>
this is home
<button onClick={() => navigate('/about')}>跳去关于页面</button>
</div>
)
}
const About = () => <div>this is about</div>
const App = () => {
return (
<div className='app'>
<BrowserRouter>
<Link to='/'>首页 | </Link>
<Link to='about'>关于</Link>
<Routes>
<Route path='/' element={<Home />}></Route>
<Route path='/about' element={<About />}></Route>
</Routes>
</BrowserRouter>
</div>
);
};
export default App;
当然,history
可以有回退的功能,就是可以缓存历史访问的页面,你想要关掉这个功能,只需要给 navigate
加入第二个参数: replace: true
<button onClick={() => navigate('/about' , { replace: true })}>跳去关于页面</button>
这样,你就无法回退了
你会发现 react 中需要引入的东西还是蛮多的,这里也总结下
BrowserRouter,HashRouter
history
模式和 hash
模式
Link
to
属性用于跳到指定的路径
Routes
路由的入口,类似 vue
的 router-view
Route
单个路由匹配,path
用于匹配路径,element
用于匹配组件
useNavigate
const navigate = useNavigate()
路由传参
之前讲 vue
的路由传参有四种方法,这里 react
有两种方式进行传参
方法一:Search传参
这种方式就是原生 js
写法,直接 ?
拼接 url
后面传递
其他页面想要拿到这个参数需要引入一个 hooks
,useSearchParams
,这个方法的实例是一个数组,数组中用 get
拿到参数
import React from 'react';
import { BrowserRouter, Link, Routes, Route, useNavigate, useSearchParams } from 'react-router-dom'
const Home = () => {
const navigate = useNavigate()
return (
<div>
this is home
<button onClick={() => navigate('/about?id=123' , { replace: true })}>跳去关于页面</button>
</div>
)
}
const About = () => {
let [ params ] = useSearchParams()
console.log(params.get('id'));
return (
<div>this is about</div>
)
}
const App = () => {
return (
<div className='app'>
<BrowserRouter>
<Link to='/'>首页 | </Link>
<Link to='about'>关于</Link>
<Routes>
<Route path='/' element={<Home />}></Route>
<Route path='/about' element={<About />}></Route>
</Routes>
</BrowserRouter>
</div>
);
};
export default App;
你若用 Link
这样跳转页面,useSearchParams
是拿不到参数的,这种方法只能用 navigate
方法二:Params传参
这种方法你就可以传参不用 ?
,直接用 /
拼接即可,为了防止这个参数也是个路径,你需要在接收方引入一个 hooks
,useParams
,并且传参时需要在 Routes
中的路径中指明 path
有参数,并且用:
写上参数名
import React from 'react';
import { BrowserRouter, Link, Routes, Route, useNavigate, useSearchParams, useParams } from 'react-router-dom'
const Home = () => {
const navigate = useNavigate()
return (
<div>
this is home
<button onClick={() => navigate('/about/123' , { replace: true })}>跳去关于页面</button>
</div>
)
}
const About = () => {
let params = useParams()
console.log(params.id);
return (
<div>this is about</div>
)
}
const App = () => {
return (
<div className='app'>
<BrowserRouter>
<Link to='/'>首页 | </Link>
<Link to='about'>关于</Link>
<Routes>
<Route path='/' element={<Home />}></Route>
<Route path='/about/:id' element={<About />}></Route>
</Routes>
</BrowserRouter>
</div>
);
};
export default App;
其实还有个 state
传参,不过现在最新的react版本已经不支持了
总结
- navigate('/about?id=123') 用
useSearchParams()
接受参数 - navigate('/about/123') 用
useParams()
接受参数
二级路由
下面实现一个二级页面的效果,一个布局栏页面中又有一个文章页面和一个发布页面
App.jsx
import React from 'react';
import { BrowserRouter, Routes, Route } from 'react-router-dom'
import Home from './views/Home';
import Layout from './views/Layout';
import Article from './views/layout-views/Article'
import Publish from './views/layout-views/Publish'
const App2 = () => {
return (
<div>
<BrowserRouter>
<Routes>
<Route path='/' element={<Home />}></Route>
{/* 二级路由 */}
<Route path='/layout' element={<Layout />}>
<Route path='article' element={<Article/>}></Route>
<Route path='publish' element={<Publish/>}></Route>
</Route>
</Routes>
</BrowserRouter>
</div>
);
};
export default App2;
Layout.jsx
import React from 'react';
import { Link, Outlet } from 'react-router-dom'
const Layout = () => {
return (
<div>
<header style={{height: '80px', backgroundColor: '#eee'}}>header</header>
<section style={{display: 'flex'}}>
<aside style={{width: '200px', height: 'calc(100vh - 80px)', backgroundColor: 'yellow'}}>
<ul>
<li><Link to={'/layout/article'}>文章</Link></li>
<li><Link to={'/layout/publish'}>发布</Link></li>
</ul>
</aside>
<section>
<Outlet />
</section>
</section>
</div>
);
};
export default Layout;
这里的写法和 vue 有异曲同工之妙,二级路由无需打斜杠 /
,同样的在 layout
中再写一个 Route
二级路由需要引入一个入口 Outlet
,Route
中的页面才会在这里面展示
当然,我们也可以来到 layout
默认展示一个二级页面,实现方法有两种,这里以默认展示 article
页面为例
实现方法一:直接将 article
的 path
去掉,换成 index
{/* 二级路由 */}
<Route path='/layout' element={<Layout />}>
<Route index element={<Article/>}></Route>
<Route path='publish' element={<Publish/>}></Route>
</Route>
这样做,article
的路径就是 layout
的路径
实现方法二: Navigate
{/* 二级路由 */}
<Route path='/layout' element={<Layout />}>
<Route path='' element={<Navigate to='/layout/article'/>}></Route>
<Route path='article' element={<Article/>}></Route>
<Route path='publish' element={<Publish/>}></Route>
</Route>
写法上就是再写一个Route
,用作重定向
最后
对比 vue,react 的路由写法还是比较复杂一点, react 中引入的东西还是比较多的,vue 无论一级二级路由都是一个写法,react 的写法是一级路由入口直接 BrowserRouter
,而二级路由则需要写一个Outlet
才能展示。