目录
1)直接在 package.json 中添加 proxy 属性
1、概念:
从版本的React-Router5.x开始,路由彻底改变了,和以后的版本完全不兼容。所以要注意版本。
对当页面应用模式提供多页面效果
Link和useNavigate实现组件切换时,实计上伴随着组件的销毁与创建,所以建议只有整体页面切换时才使用路由,而局部切换时使用最原始的隐藏显示为佳,这样可以保让组件中通过ajax得到的数据一直存在。同样的道理,子路由的使用也需要特别小心。
2、环境
(1)下载第三方模块
(a)ts开发情况下,
下载模块"react-router-dom"和 "@types/react-router-dom"
npm i --save react-router-dom @types/react-router-dom
(b)js开发情况下,
只需下载模块"react-router-dom"
(2)引入
BrowserRouter 与history模式类似,HashRouter与hash模式类似
BrowserRouter和HashRouter两者的区别,和vue中history和hash的区别一样,面试回答vue中的就可以了
BrowserRouter和HashRouter只能二选一,而且这两个标签只用一次,子路由中也不要使用(如果用了不会报错,但是会很奇怪),一个网站只用一次
BrowserRouter太长,常常使用别名Router,as是给BrowserRouter换一个变量名
import {
BrowserRouter as Router, //BrowserRouter太长,常常使用别名Router,Router:是自己取的名字,是一个类型别名
Route,
Routes, //专门注册网址的,
Link,
useNavigate,
useParams,
useLocation,
Navigate
} from 'react-router-dom';
3 创建路由
<BrowserRouter>
<Routes>
<Route path='/main' element={<Main />} />
<Route path='/one' element={<One />} />
<Route path='/two' element={<Two />} />
</Routes>
</BrowserRouter>
<BrowserRouter>
{/*Nav这个自定义组件与路由出来的界面同时显示, 页面跳转-Link和useNavigate可以在该组件中控制*/}
<Nav />
<Routes>
<Route path='/main' element={<Main />} />
<Route path='/one' element={<One />} />
<Route path='/two' element={<Two />} />
</Routes>
</BrowserRouter>
4 页面跳转-Link和useNavigate
Link相当于超连接
useNavigate是hook
import {Link, useNavigate} from 'react-router-dom';
Line标签
<Link to={{pathname:'/one'}}>one</Link>
或ts代码-useNavigate
let navigate = useNavigate();
function toTwo() {
navigate({pathname:'/one'});
navigate('/one'});
}
5 路由使用注意事项
Link和useNavigate实现组件切换时,实计上伴随着组件的销毁与创建,
所以建议只有整体页面切换时才使用路由,
而局部切换时使用最原始的隐藏显示为佳,
这样可以保让组件中通过ajax得到的数据一直存在。
同样的道理,子路由的使用也需要特别小心
6 传参数
三种方式:
1、通过url传参数(有种类型:Link, useNavigate)、
2、动态传参数、
3、state(参数不会显示在页面上),更常用
1 )通过url传参数
传:import {Link, useNavigate} from 'react-router-dom';
接收:import {useLocation} from 'react-router-dom';
url的组成:
协议 //ip:port/pathname search hash
search ?querystring
querystring key=value&key2=value2
hash #/home/car?dat=123
//传参 方式一:Link to
传参:
<Link to='/one?name=泪王'>传参</Link>
<Link to={{pathname:"home",search:"goods=123"}}>传参</Link>
//传参 方式二:useNavigate
let navigate = useNavigate();
function to() {
navigate({pathname:"home",search:"goods=123"});
}
接收1:
import {useLocation} from 'react-router-dom';
let location = useLocation();
let search = location.search;
search = decodeURI(search);//转码 decodeURI浏览器自带的函数,有中文就可以使用这个函数进行转码
console.log(search);// /one?name=泪王
接收2:自己封装,将query解成对象
import {useLocation} from 'react-router-dom';
let location=useLocation()
let obj=location.search.queryobj()
String.prototype.queryobj=function (){
let obj={}
this.split("?"[i].split("&").map(el=>{
let arr=el.split("=")
obj[arr[0]]=arr[1]
}))
return obj
}
2 )动态传参数
<Route path='/two/:name/:sex' element={<Two />} />
name和sex 是变量名,可以随便写,只要前面是/two,就可以匹配到/two页面
也就是/:name/:sex随便写(但是必须写),都可以加载同一个组件用法:根据自己后面传的动态参数,给页面加载不同的内容
第一步设置可传参数
设置可传参数
<Route path='/two/:name/:sex' element={<Two />} />
第二步传参数
传参
navigate({pathname:`/two/小王/女`});
navigate("/two/小王/女");
或
<Link to={{pathname:`/two/小王/女`}}>two</Link>
<Link to="/two/小王/女">two</Link>
第三步使用hook-useParams函数接收参数
接收参数 (在跳转到的页面中)
import {Link, useParams} from 'react-router-dom';
let person = useParams();
console.log(person.name,person.sex) //小王 女
3 )state传参数
state的参数不会在页面上显示
使用场景:比如token码,一些隐蔽的参数
search和state可以同时使用
//传递参数关键代码
import {useNavigate} from 'react-router-dom';
let navigate = useNavigate();
//1、
navigate({pathname:'/one'},{state:{id:1,sex:'女',name:'小五'}});
//2、
navigate({pathname:'/one',search:"?page=10"},{state:{id:1,sex:'女',name:'小五'}});
//3、
<Link to={{pathname:'/one'}},state:{{id:1,sex:'女',name:'小五'}}>two</Link>
接收参数使用hook-useLocation函数,接收到的对象state是一个Object类型,
所以必须类型断言才能取出属性值
//接收参数关键代码
import {useLocation} from 'react-router-dom';
const location = useLocation();
let stu = location.state as {id:number,sex:string,name:string};
vue3.0中跳转传参也有 state
7 配置符 *
<Route path="/*" element={<组件1 />}></Route>
<Route path="/test" element={<组件2 />}></Route>
{/*
/test匹配到组件2
/teacher匹配到组件1
*/}
8 子路由 / 理由嵌套
父路由已经注册 import {BrowserRouter } from 'react-router-dom',并且使用了<BrowserRouter></BrowserRouter>,在子组件和其它任何组件都不用再引入和在使用了
BrowserRouter和HashRouter只能二选一,而且这两个标签只用一次,子路由中也不要使用(如果用了不会报错,但是会很奇怪),一个网站只用一次
1 )子路由配置
方式1:
第1步 在配置 主路由 的path属性后面 加 "/*" ,eg: path="/one/*"
//router.jsx
<BrowserRouter>
<Routes>
<Route path="/" element={<Main />}></Route>
<Route path="/one/*" element={<One />}></Route>
</Routes>
</BrowserRouter>
第2步:在主路由对应的组件中使用配置新的路由, 子路由的访问path为 "主路由+子路由"
/one 匹配到<Person />
/one/stu 匹配到组件<Stu />
/one/aabb 匹配不到组件
//One.jsx
<Routes> //因为父组件写了<BrowserRouter></BrowserRouter>,所以其它的组件就不写了
<Route path="/" element={<Person />} />
//stu是相对于当前的网址,不用加父组件的One了
<Route path="/stu" element={<Stu />} />
//下面这种写法是错的,匹配不到。 //
<Route path="/One/boss" element={<Boss />} />
</Routes>
方式2:
router.jsx
<Route path="/test" element={<Test />}>
<Route path="/a" element={<Testa />}>
</Route >
</Route >
src/views/test/Index.jsx
import React, { useState } from 'react'
import {Outlet} from "react-router-dom"
export default function Index() {
return (
<div>
<Outlet></Outlet>
</div>
)
}
src/views/test/testa.jsx
import React, { useState } from 'react'
export default function Index() {
return (
<div>
<p>testa</p>
</div>
)
}
2 )主路由与子路由相互跳转
不管是主路由还是子路由,都可以在浏览器中输入正确的地址访问到;
不管是主路由还是子路由,只要组件内嵌在标签"BrowserRouter"中,就可以使用hook-useNavigate或标签Link直接使用正确的路由path访问到;
9 重定向
1 )重定向基础
方式1:在 Route 的 element 中使用
重定向需使用到组件Navigate ==> import {Navigate} from 'react-router-dom';
Route中的element不设置组件,而设置别的已经设置好的Route的path, 显示效果就是该path对应的组件。
子路由可以重定向到主路由,主路由中也可以重定向到子路由。
<Routes>
<Route path="/" element={<Main />}></Route>
<Route path="/one/*" element={<One />}></Route>
<Route path="/two" element={<Two />}></Route>
<Route path="/three" element={<Three />}></Route>
<Route path="/*" element={<Page404 />}></Route>
{/* 主路由重定向到主路由: 重定向到path:/two对应的组件<Two />中, 网址会显示为/two */}
<Route path="/b" element={<Navigate to="/two" />} />
{/* 主路由重定向到子路由: 定向到path:/one/stu对应的组件XXX中,网址会显示为/one/stu */}
<Route path="/a" element={<Navigate to="/one/stu" />} />
</Routes>
方式2 : 在组件的返回值中使用
<Route path="/a" element={<Index/>} />
import React from 'react';
import {Navigate} from 'react-router-dom';
export default function Index(flag:string) {
if(flag=="stu") {
return <Navigate to="/one" replace={true} />
}else {
return <Navigate to="/two" replace={true} />
}
}
2 )路径错误默认显示页面
主路由中使用 /* 来匹配,子路由中重定向到主路由中的 /*
//App.tsx 第一级路由(主路由)
<Route path="/" element={<Main />}></Route>
<Route path="/one/*" element={<One />}></Route>
<Route path="/two" element={<Two />}></Route>
<Route path="/three" element={<Three />}></Route>
<Route path="/*" element={<Page404 />}></Route>
<Page404 />是路由错误的默认访问网页
localhost:3000--<Main>
localhost:3000/one--<One>
localhost:3000/two--<Two>
localhost:3000/three---<Three>
localhost:3000/aabb---<Page404>
//One.tsx 第二级路由(子路由)
<Routes>
<Route path="/boss" element={<Boss />} />
<Route path="/*" element={<Navigate to="/404" />} />
</Routes>
localhost:3000/one/boss--<Boss>
localhost:3000/one/aabb--重定向到localhost:3000/404--匹配主路由的/*---找到<Page404 />
<Navigate to="/404" />中的"/404"是任意写的一个不存在的路由path,所以不是非要写成"/404"
10 路由首守-登陆判断
方法1:
写一个带插槽的组件,在该组件中统一判断是否登陆,进而决定该组件中插入的组件是否正常加入。
在路由配置组件时,所有组件使用插槽组件包裹。
src/router/index.jsx
import React,{useState} from 'react';
import {BrowserRouter,Link, Routes, Route, Navigate} from 'react-router-dom';
import Main from './Main';
import Login from '../views/Login';
import Goods from '../views/Goods';
import About from './About';
import RouterFilter from './RouterFilter';
function Index() {
const[islogin, setIslogin] = useState<boolean>(false);
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<RouterFilter><Main /></RouterFilter>}></Route>
<Route path="/goods" element={<RouterFilter><Goods /></RouterFilter>}></Route>
<Route path="/about" element={<RouterFilter><About /></RouterFilter>}></Route>
<Route path="/login" element={<Login />}></Route>
</Routes>
</BrowserRouter>
);
}
export default Index;
src/router/RouterFilter.jsx
import React,{useContext} from 'react'
import MyContext from './MyContext';
import {Navigate} from 'react-router-dom';
function RouterFilter({children}:any) {
if(已经登陆) {
return children;
}else {//未登陆
return <Navigate to="/login" replace={true} />
}
}
export default RouterFilter;
方法2:
通过属性传值的方式,进行判断
src/router/index.jsx
import React from 'react'
import {BrowserRouter,Routes,Route} from "react-router-dom"
import OAuth from "./oAuth"
import Home from "../views/home"
import Login from "../views/login"
import Register from "../views/register"
import User from "../views/user"
import Car from "../views/car"
import Root from "../views/root"
export default function Router() {
return (
<BrowserRouter>
<Routes>
<Route path='/' element={<Home/>}></Route>
<Route path='/home' element={<Home/>}></Route>
<Route path='/login' element={<Login/>}></Route>
<Route path='/register' element={<Register/>}></Route>
<Route path='/user' element={<OAuth Component={User}/>}></Route>
<Route path='/car' element={<OAuth Component={Car}/>}></Route>
<Route path='/root' element={<OAuth Component={Root}/>}></Route>
</Routes>
</BrowserRouter>
)
}
src/router/oAuth.jsx
import React from 'react'
import {Navigate} from "react-router-dom"
export default function OAuth({Component}) {
console.log(Component)
let token=window.localStorage.getItem("token")
if(token){
return (<Component></Component> )
}
else{
return <Navigate to="/login"></Navigate>
}
}
11 React解决跨域
1)直接在 package.json
中添加 proxy
属性
只适用于只有一个后台服务器,后端不用写cors了
在前端的 package.json文件中:
"proxy":"http://localhost:7001/"
2)安装 http-proxy-middleware
:
适用于多个后台服务器
安装 http-proxy-middleware
:
npm install http-proxy-middleware
或者
yarn add http-proxy-middleware
这里注意,http-proxy-middleware 模块是有版本区别的,默认安装最新版本,然后在 src 目录下新建 setupProxy.js
:
const { createProxyMiddleware } = require("http-proxy-middleware");
module.exports = function (app) {
app.use(
"/api",
createProxyMiddleware({
target: "http://localhost:3000", // 后台服务地址以及端口号
changeOrigin: true, // 是否开启代理
pathRewrite: {
"/api": "", // 代理名称
},
})
);
};
重新 npm run start
即可解决跨域
3)npm run eject
已经进行了 npm run eject
,就直接修改 config>webpackDevServer.config.js
:
module.exports = function (proxy, allowedHost) {
const disableFirewall =
!proxy || process.env.DANGEROUSLY_DISABLE_HOST_CHECK === 'true';
// 配置proxy对象解决跨域
proxy = {
...proxy,
'/api': {
target: 'http://localhost:3000', // 后台服务地址以及端口号
changeOrigin: true, //是否跨域
pathRewrite: { '^/api': '/' },// 代理名称
secure: false
},
}
return {
......
}