现代的前端应用大多都是 SPA(单页应用程序)single page application,也就是只有一个 HTML 页面的应用程序。因为它的用户体 验更好、对服务器的压力更小,所以更受欢迎。
为了有效的使用单个页面来管理原来多页面的功能,前端路由 应运而生。
前端路由的功能:让用户从一个视图(页面)导航到另一个视图(页面)
帮助我们实现组件之间的动态切换。
作用:包裹整个应用,一个 React 应用只需要使用一次
两种常用 Router : HashRouter 和 BrowserRouter
使用 URL 的哈希值实现(http://localhost:3000/#/first)
BrowserRouter ( 推荐 )
使用 H5 的 history.pushState API 实现(http://localhost:3000/first)
作用 :用于指定导航链接,完成路由跳转
语法说明: 组件通过to属性指定路由地址,最终会渲染为a链接元素
作用 :提供一个路由出口,满足条件的路由组件会渲染到组件内部,定义path和组件的对应关系
作用 :用于指定导航链接,完成路由匹配
语法说明: path属性指定匹配的路径地址,element属性指定要渲染的组件
说明:当url路径为 ‘/about’ 时,会渲染
1.安装:yarn add react-router-dom
- npm install react-router-dom@6
- //新版
2.导入路由的三个核心组件:Router / Routes / Route/Link
import { BrowserRouter as Router, Routes, Route, Link } from 'react-router-dom'
3.使用 Router 组件包裹整个应用(重要)
- <Router>
- <div className="App">
- // … 省略页面内容
- div>
- Router>
4.用Routes包裹内部Route页面内容
- <Routes>
- <Route path="/" element>Route>
- <Route path="/first" element={<First />}>Route>
- Routes>
5.使用 Link 组件作为导航菜单(路由入口)(Link指定跳转的对应路由组件的路径,to是用来配置路由地址)
<Link to="/first">页面一Link>
6.使用 Route 组件配置路由规则和要展示的组件(路由出口),在子路由外面用Routes包裹
- const First = () => <p>页面一的页面内容p>
-
- // 使用Router组件包裹整个应用
- const App = () => (
- <Router>
- <div>
- <h1>React路由基础h1>
- {/* 指定路由入口 */}
- <Link to="/first">页面一Link>
- //路由出口:路由地址对应的组件会在这里进行渲染
- <Routes>
- <Route path="/" element>Route>
- {/* 指定路由出口 */}
- //指定路径和组件之间的映射关系。path:路径;element:组件,成对出现
- <Route path="/first" element={<First />}>Route>
- Routes>
- div>
-
- )
添加一个代码,可以避免警告。
添加一个 “/” 路径的路由
<Route path="/" element>Route>
验证:
1.http://localhost:3000/ ,删除first,显示以下内容。
2.点击页面一后,显示First页面,显示 ’页面一的内容‘ 。
两种常用的路由模式:BrowserRouter和HashRouter
BrowserRouter | 声明当前要用是一个非hash的模式的路由 包裹整个应用 一个React应用只需要使用一次 HashRouter,hash模式的路由 一个有#(HashRouter),一个一带#(BrowserRouter)(推荐) |
Link | 指定导航链接,完成路由跳转 to属性指定路由地址,最终被渲染为a标签 |
Routes | 提供一个路由出口,满足条件的路由组件,会渲染到组件内部 |
Route | 用于指定路由组件和路由地址 path:路由组件对应的路径;element:路由组件;成对出现 |
- // to属性:浏览器地址栏中的pathname(location.pathname)
- --点击a标签,就会改变浏览器地址栏中的内容了
-
- <Link to="/first">页面一Link>
- // path属性:路由规则
- // element:展示的组件
- // Route组件写在哪,渲染出来的组件就展示在哪
-
- <Route path="/first" element={<First />}>Route>
跳转 --- 通过js编程的方式进行页面路由的跳转。
1.场景:点击登录按钮,登录成功后,通过代码跳转到后台首页,如何实现?
2.编程式导航:通过 JS 代码来实现页面跳转
更适合携带参数跳转到另一个页面
使用useNavigate跳转,还有一种方法是this.props.history,但是这种方法有的组件不一定能拿到this.props的值
3. history 是 React 路由提供的,用于获取浏览器历史记录的相关信息
4. push(path):跳转到某个页面,参数 path 表示要跳转的路径
5. go(n): 前进或后退到某个页面,参数 n 表示前进或后退页面数量(比如:-1 表示后退到上一页)
- class Login extends Component {
- handleLogin = () => {
- // ...
- this.props.history.push('/home')
- }
- render() {...省略其他代码}
- }
1.导入路由
import { BrowserRouter as Router, Routes, Route, Link } from 'react-router-dom'
2.用Router包裹整个应用
- <Router>
- <div>
- <h1>编程式导航:h1>
- div>
- Router>
3.Link创建导航菜单
<Link to="/login"> 去登录页面Link>
4.配置路由规则
- <Route path="/" element>Route>
- <Route path="/login" element={<Login />}>Route>
- <Route path="/home" element={<Home />}>Route>
5.用Routes包裹所有的Route
- <Routes>
- <Route path="/login" element={<Login />}>Route>
- ...
- Routes>
6.中途检验:
1.回到http://localhost:3000/地址,显示
2.点击 去登录页面,显示
7.给按钮绑定点击事件
- handleLogin = () => {
- // 使用编程式导航实现路由跳转
- // ...省略其他功能代码
- this.props.history.push('/home')
- }
-
-
报错:
执行useNavigate函数会得到一个跳转函数。
- const navigate = useNavigate()
- navigate('/home');
报错:https://reactjs.org/warnings/invalid-hook-call-warning.html
为避免混淆,其他情况下不支持调用 Hooks:
🔴 不要在类组件中调用 Hooks。
🔴 不要调用事件处理程序。
🔴不要在传递给 useMemo, useReduce ,useEffect 的函数中调用 Hooks
最后,改类组件,变函数,用useNavigate完成
- import { useNavigate } from 'react-router-dom'
-
- const Login = props => {
- const navigate = useNavigate()
- const handleLogin = () => {
- navigate('/home')
- }
- return (
- <div>
- <p>登录页面:p>
- <button onClick={handleLogin}>登录button>
- div>
- )
- }
1.声明Login小组件
- function Login () {
- return (
- <div>Logindiv>
- )
- }
- export default Login
2.加入App中
- import Login from './Login'
-
- <Route path="login" element={<Login />}>Route>
3.Login跳到About
import {useNavigate} from 'react-router-dom'
- const navigate = useNavigate()
-
-
- // 跳转到About页
- function goAbout(){
-
- }
- function goAbout(){
- navigate('/about')
- }
navigate('/about',{replace:true})
注意:如果在跳转时不想加历史记录,可以添加额外参数replace为true
- //导入react
- import React from 'react'
- import { createRoot } from 'react-dom/client';
-
- // 导入路由
- import { BrowserRouter as Router, Routes, Route, Link, useNavigate } from 'react-router-dom'
-
- const Login = props => {
- const navigate = useNavigate()
- const handleLogin = () => {
- navigate('/home')
- }
- return (
- <div>
- <p>登录页面:p>
- <button onClick={handleLogin}>登录button>
- div>
- )}
-
-
- const Home = props => {
- const navigate = useNavigate()
- const handleBack = () => {
- navigate('/login')
- }
- return (
- <div>
- <h2>我是后台首页h2>
- {/* 函数里面没有this了 */}
- <button onClick={handleBack}>返回登录页面按钮button>
- div>
- )}
-
- // 使用Router组件包裹整个应用
- const App = () => (
- <Router>
- <div>
- <h1>编程式导航:h1>
- <Link to="/login"> 去登录页面Link>
- <Routes>
- <Route path="/" element />
- <Route path="/login" element={<Login />} />
- <Route path="/home" element={<Home />} />
- Routes>
- div>
- Router>
- )
-
-
- const container = document.getElementById('root');
- const root = createRoot(container);
- root.render(<App />);
- import { BrowserRouter as Router, Routes, Route, useNavigate } from 'react-router-dom'
- function Home () {
- // 执行useNavigate函数会得到一个跳转函数
- const navigate = useNavigate()
- function goAbout () {
- //跳转到关于页面,调用跳转函数转入参数(目标路径)
- // 如果在跳转时,不想添加历史记录,可以设置第二个参数,传入对象,对象中有replace:true
- navigate('/about', { replace: true })
- }
- return (
- <div>
- <h2>首页h2>
- <button onClick={goAbout}>跳转到关于页面button>
- div>
- )}
- function About () {
- return (
- <div>
- <h2>关于h2>
- div>
- )}
-
- function App () {
- return (
- <Router>
- <Routes>
- <Route path="/" element={<Home />} />
- <Route path="/about" element={<About />} />
- Routes>
- Router>
- )}
- export default App
npm i react-router-dom@5.0
1.初始代码
- // 导入路由
- import { BrowserRouter as Router, Route, Link } from 'react-router-dom'
-
- class Login extends React.Component {
- handleLogin = () => {
- // 使用编程式导航实现路由跳转
- // ...省略其他功能代码
-
- this.props.history.push('/home')
- }
- render() {
- return (
- <div>
- <p>登录页面:p>
- <button onClick={this.handleLogin}>登录button>
- div>
- )
- }
- }
-
- const Home = () => (
- <div>
- <h2>我是后台首页h2>
- div>
- )
-
- // 使用Router组件包裹整个应用
- const App = () => (
- <Router>
- <div>
- <h1>编程式导航:h1>
- <Link to="/login"> 去登录页面Link>
- <Route path="/login" component={Login}>Route>
- <Route path="/home" component={Home}>Route>
- div>
- Router>
- )
2.完整代码
- //导入react
- import React from 'react'
- import ReactDOM from 'react-dom'
- // 导入路由
- import { BrowserRouter as Router, Route, Link } from 'react-router-dom'
-
- class Login extends React.Component {
- handleLogin = () => {
- // 跳转到具体的页面
- this.props.history.push('/home')
- }
- render() {
- return (
- <div>
- <p>登录页面:p>
- <button onClick={this.handleLogin}>登录button>
- div>
- )
- }
- }
-
- const Home = props => {
- const handleBack = () => {
- //go(-1)返回上一个页面
- props.history.go(-1)
- }
- return (
- <div>
- <h2>我是后台首页h2>
- {/* 函数里面没有this了 */}
- <button onClick={handleBack}>返回登录页面按钮button>
- div>
- )
- }
-
- // 使用Router组件包裹整个应用
- const App = () => (
- <Router>
- <div>
- <h1>编程式导航:h1>
- <Link to="/login"> 去登录页面Link>
- <Route path="/login" component={Login} />
- <Route path="/home" component={Home} />
- div>
- Router>
- )
-
- ReactDOM.render(<App />, document.getElementById('root'))
跳转携带参数
场景 :有些时候不光需要跳转路由还需要传递参数
1.传参
navigate('/about?id=1', { replace: true })
2.取参
导入钩子函数
import {useSearchParams} from 'react-router-dom'
执行钩子函数
- // params是一个对象,对象里面有一个get的方法
- // 用来获取对应的参数
- // 把参数的名称作为get方法的实参传过来
- const [params] = useSearchParams()
把参数的id作为get方法的实参传过来
const id = params.get('id')
把id渲染出来
<div>about得到的参数id值为:{id}div>
如果要在id后面拼接name(id&name)
- function About () {
- const [params] = useSearchParams()
- const id = params.get('id')
- const name = params.get('name')
-
- return (
- <div>about得到的参数id值为:{id}{name}div>
- )
- }
在页面搜索
http://localhost:3000/about?id=1&name='zz'
查看params有什么方法
console.log(params)
当输入了两个id,以第一个id为主
http://localhost:3000/about?id=1&name='zz'&id=111
最后结果:id=1
- import { BrowserRouter as Router, Routes, Route, useNavigate, useSearchParams } from 'react-router-dom'
- function Home () {
- const navigate = useNavigate()
- function goAbout () {
- navigate('/about?name=zz&age=10', { replace: true })
- }
- return (
- <div>
- <h2>首页h2>
- <button onClick={goAbout}>跳转到关于页面button>
- div>
- )}
- function About () {
- console.log(useSearchParams())//0:数组;1.回调函数
- const [params] = useSearchParams()
- console.log(params.get('name'))//想要拿去哪个参数,就在get里传字符串形式的参数
- // 定义变量,进行接收
- const name = params.get('name')
- return (
- <div>
- <h2>关于h2>
- <h2>{name}h2>
- <h2>{params.get('name')}h2>
- div>
- )}
-
- function App () {
- return (
- <Router>
- <Routes>
- <Route path="/" element={<Home />} />
- <Route path="/about" element={<About />} />
- Routes>
- Router>
- )}
1.修改
navigate('/about/1', { replace: true })
<Route path="/about/:id" element={<About />}>Route>
2.取参
- import { useParams } from 'react-router-dom'
- function About () {
- const params = useParams()
- // params为对象
- console.log(params)
-
- return (
- <div>about得到的参数id值为:{params.id}div>
- )
- }
- import { BrowserRouter as Router, Routes, Route, useNavigate, useParams } from 'react-router-dom'
- function Home () {
- const navigate = useNavigate()
- function goAbout () {
- navigate('/about/01', { replace: true })
- }
- return (
- <div>
- <h2>首页h2>
- <button onClick={goAbout}>跳转到关于页面button>
- div>
- )
- }
- function About () {
- console.log(useParams())
- const params = useParams()
- return (
- <div>
- <h2>关于h2>
- <h2>{params.id}h2>-->可以拿到01
- div>
- )
- }
-
- function App () {
- return (
- <Router>
- <Routes>
- <Route path="/" element={<Home />} />
- <Route path="/about/:id" element={<About />} />
- Routes>
- Router>
- )
- }
- export default App
- function Home () {
- const navigate = useNavigate()
- const [id] = useState(10)
- function goAbout () {
- navigate('/about/' + id)
- }}
<Route path="/" component={Home} />
- <Link to="/login">登录页面Link>
- <Route path="/" component={Home} /> 匹配成功
path:代表Route组件的path属性
pathname:代表Link组件的to属性(也就是 location.pathname)
- // 此时,该组件只能匹配 pathname=“/” 这一种情况
- <Route exact path="/" component=... />
推荐:给默认路由添加 exact 属性。
一个路由页面里面,还有路由页面,根据路由路由跳转 。
对于二级路由的路径,可以不用写 “ / ”
Home.js
- import React from 'react'
- import { Link, Outlet } from 'react-router-dom'
- // 类子组件
- function Home () {
- return (
- <div>
- <h2>首页h2>
- <Link to="news">新闻Link>
- <Link to="share">分享Link>
- {/* 设置二级路由出口 */}
- <Outlet />
- div>
- )}
-
- // 导出组件
- export default Home
App.js
- import Home from './Home'
- import News from './News'
- import Share from './Share'
- import { BrowserRouter as Router, Routes, Route } from 'react-router-dom'
- function App () {
- return (
- <Router>
- <Routes>
- <Route path="/" element={<Home />} >
- {/* 定义嵌套关系,首页中嵌套路由 */}
- <Route path="news" element={<News />} />
- <Route path="share" element={<Share />} />
- Route>
- Routes>
- Router>
- )}
- export default App
将本身的path去除掉,添加属性index
1.给默认路由标记index,
2.修改跳转路径path->删除
App.js
<Route index element={<News />} />
Home.js
直接跳转到首页,就可以显示新闻页面了
<Link to="/">新闻Link>
写在所有路径的最下面
场景 :当所有的路径都没有匹配的时候显示
语法说明: 在各级路由的最后添加 * 号路由作为最后的路由。
- import NotFound from './NotFound'
- //当所有的路径都没有匹配时,就显示404页面
- <Route path="*" element={<NotFound />} >Route>
准备两个按钮,点击不同按钮切换不同内容显示。
1.创建About.js,Home.js
- function Home (){
- return(
- <div>aboutdiv>
- )
- }
- export default Home
2.App.js引入这两个组件
- import Home from './Home'
- import About from './About'
3.进行路由配置
import {BrowserRouter,Routes,Route,Link} from 'react-router-dom'
4.点击跳转和路由出口配置
- function App () {
- return (
- <Router>
- {/* 点击跳转 */}
- // 指定跳转的组件 to用来配置路由地址
- <Link to="/">首页Link>
- <Link to="/about">关于Link>
- {/* 路由出口位置 */}
- // 路由对应的组件会在这里进行渲染
- <Routes>
- // 指定路径和组件的对应关系 path代表路径 element代表组件 成对出现
- // path->element
- <Route path="/" element={<Home />}>Route>
- <Route path="about" element={<About />}>Route>
- Routes>
- Router>
- )
- }