相关理解 
SPA:单页面应用
整个应用只有一个完整的页面 
点击页面链接不会刷新页面,只会页面局部更新 
数据通过ajax请求获取,在前端异步展现 
 
 
路由【一个路由就是一个映射关系(key:value)key:路径 value:function或者component】
后端路由【value是function,处理客户端提交的请求】
注册路由:router.get(path,function(req,res)) 
工作流程:当node接收到请求,根据请求路径找到匹配的路由,调用路由中的函数处理请求,返回请求数据 
 
 
前端路由【浏览器路由,values是component,用于展示页面内容】
注册路由 <Route path="/test" component={Test}> 
工作过程:当浏览器的path变成/test,前端路由组件就会变成Test组件  
 
 
 
 
react-router
react 的一个插件库 
专门实现SPA应用 
基于react 项目基本都会用到此库 
 
 
 
react-router相关API 
内置组件
<BrowserRouter><HashRouter><Route><Redirect> ——————react-router-dom@6取消了重定向方法<link><NavLink><Switch> ——————<Switch>重命名为<Routes> 
 
其他
history对象 
match对象 
withRouter对象 
 
 
注意事项
Route 组件必须包裹 Routes 组件 
Route 组件属性由原来的 component 改为了 element 
a标签由 Link组件代替 to跳转路径
<Link className="list-group-item" to="/about">About</Link> 
 
渲染的时候 App组件 包裹 BrowserRouter 或者 HashRouter
ReactDOM.render(<BrowserRouter><App/></BrowserRouter> ,document.getElementById('root')); 
 
Navlink组件 改样式【v6版 支持小写 activeclassname=’active’】【v5 activeClassName】
<NavLink className={({ isActive }) => "list-group-item" + (isActive ? " active1" : "")}  to="/about">About</NavLink> 
 
标签体内容是一个特殊的标签属性【this.props.children获取】 【对NavLink 封装到 MyNavLink组件】
<MyNavLink name='About' to="/about" a={1} a={100} a='12'>About</MyNavLink>1 2 3 4 5 // v6 <Routes>   <Route path="/about" element={<About></About>}></Route>   <Route path="/home" element={<Home></Home>}></Route> </Routes> 
 
 
 
 
路由组件和一般组件
存放位置:一般组件【components】路由组件【pages】 
写法:一般组件<demo/> 路由组件 <Route path="/home" element={<Home></Home>}></Route> 
接收到的props不同【v5版】:  一般组件【写什么接收什么】 路由组件【v5:接收三个固定属性:history、localtion、match】 
 
 
 
Switch组件
通常情况下,path和component是一一对应的关系。 
Switch可以提高路由匹配效率(单一匹配)。1 2 3 4 5 6 // v5 <Switch>     <Route path="/home" component={Home}></Route>     <Route path="/about" component={About}></Route>     <Route path="/about" component={Test}></Route> </Switch> 
 
 
 
v5 : 精准匹配 与 模糊匹配 【 开启精准匹配: exact={true}】
<Route exact={true} path="/about" element={<About></About>}></Route> 
 
v5 : Redirect 重定向 v6 :Navigate useNavigate
//v5 <Redirect to="/about"></Redirect>//v6 <Route path="*" element={<Navigate to="/about"/>} /> 
 
 
 
嵌套路由【v6】 1 2 3 4 5 6 7 8 9 10 11 12 // App.jsx Routes>   <Route path="/about" element={<About></About>}></Route>   <Route path="/home" element={<Home></Home>}>     <Route path="/home/news" element={<News></News>}></Route>     <Route path="/home/messages" element={<Messages></Messages>}></Route>     <Route path="/home" element={<Navigate to="/home/news" />} />   </Route>   <Route path="*" element={<Navigate to="/about" />} /> </Routes> // Home.jsx <Outlet></Outlet> 
路由传值的三种方式(v5 和 v6) 1.params参数【传参带/,路由带冒号,useParams】 
v5:
 
1 2 3 4 5 6 7 8 9 //路由链接(携带参数): <Link to='/demo/test/tom/18'}>详情</Link>  //或 <Link to={{ pathname:'/demo/test/tom/18' }}>详情</Link> //注册路由(声明接收): <Route path="/demo/test/:name/:age" component={Test}/>      //接收参数: this.props.match.params 
v6: useParams 只能在函数组件中使用<Link to={/home/messages/detail/${id}/${title}}>Child1</Link><Route path="/home/messages/detail:id/:title" component={Test}/>
 
1 2 3 4 5 6 7 8 9 10 11 //路由链接(携带参数): <Link to={{ pathname:`/b/child1/${id}/${title}` }}>Child1</Link> //或 <Link  to={`/b/child1/${id}/${title}`}>Child1</Link>  //注册路由(声明接收): <Route path="/b/child1/:id/:title" component={Test}/>      //接收参数: import { useParams } from "react-router-dom"; const params = useParams(); //params参数 => {id: "01", title: "消息1"} 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 import React, { Component } from 'react' import { useParams } from 'react-router-dom' export default function Detail() {     const {id,title} = useParams();     return (         <div>             <ul>                 <li>ID: {id}</li>                 <li>TITLE:{title}</li>                 <li>CONTENT:???</li>             </ul>         </div>     ) } 
2.search参数【传参带问号,路由不变,useSearchParams】 
v5
 
1 2 3 4 5 6 7 8 9 10 //路由链接(携带参数): <Link to='/demo/test?name=tom&age=18'}>详情</Link> //注册路由(无需声明,正常注册即可): <Route path="/demo/test" component={Test}/>          //接收参数: this.props.location.search //备注:获取到的search是urlencoded编码字符串(例如: ?id=10&name=zhangsan),需要借助query-string解析参数成对象 
v6: useSearchParams 只能在函数组件中使用<Link to={/home/messages/detail?id=${item.id}&title=${item.title}}>{item.title}</Link><Route path="/home/messages/detail" element={<Detail></Detail>}></Route>
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 //路由链接(携带参数):  <Link className="nav" to={`/b/child2?age=20&name=zhangsan`}>Child2</Link> //注册路由(无需声明,正常注册即可): <Route path="/b/child2" component={Test}/>          //接收参数方法1: import { useLocation } from "react-router-dom"; import qs from "query-string"; const { search } = useLocation(); //search参数 => {age: "20", name: "zhangsan"} //接收参数方法2: import { useSearchParams } from "react-router-dom"; const [searchParams, setSearchParams] = useSearchParams(); // console.log( searchParams.get("id")); // 12 //备注:获取到的search是urlencoded编码字符串(例如: ?age=20&name=zhangsan),需要借助query-string解析参数成对象 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 import React, { Component } from 'react' // 方式一 import { useSearchParams } from "react-router-dom"; // 方式二 // import { useLocation } from "react-router-dom"; // import qs from "query-string"; export default function Detail() {     // 1.接收参数     const [searchParams, setSearchParams] = useSearchParams();     // console.log(searchParams.get("id"));     // console.log(searchParams.get("title"));     // 2.接收参数     // const { search } = useLocation();     // let { id, title } = qs.parse(search)     return (         <div>             <ul>                 <li>ID: {searchParams.get("id")}</li>                 <li>TITLE: {searchParams.get("title")}</li>                 {/* <li>ID: {id}</li>                 <li>TITLE: {title}</li> */}                 <li>CONTENT:???</li>             </ul>         </div>     ) } 
3.state参数【传参带state属性,路由不变,useLocation,[浏览器路径:/home/messages/detail,没有带参数]】 
v5
 
1 2 3 4 5 6 7 8 9 10 //路由链接(携带参数): <Link to={{pathname:'/demo/test',state:{name:'tom',age:18}}}>详情</Link> //注册路由(无需声明,正常注册即可):  <Route path="/demo/test" component={Test}/>      //接收参数: this.props.location.state //备注:刷新也可以保留住参数 
v6<Link to={/home/messages/detail} state={{ id: item.id, title: item.title }} >{item.title}</Link><Route path="/home/messages/detail" element={<Detail></Detail>}></Route>
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 //通过Link的state属性传递参数  <Link      className="nav"      to={`/b/child2`}      state={{ id: 999, name: "i love merlin" }}   >     Child2 </Link> //注册路由(无需声明,正常注册即可): <Route path="/b/child2" component={Test}/>      //接收参数: import { useLocation } from "react-router-dom"; const { state } = useLocation(); //state参数 => {id: 999, name: "我是梅琳"} //备注:刷新也可以保留住参数 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 import React, { Component } from 'react' import { useLocation } from "react-router-dom"; {/* <Route path="/home/messages/detail" element={<Detail></Detail>}></Route> */} {/* <Link to={`/home/messages/detail`} state={{ id: item.id, title: item.title }} >{item.title}</Link> */} export default function Detail(){     const { state } = useLocation();     console.log(useLocation());     return (         <div>             <ul>                 <li>ID: {state.id}</li>                 <li>TITLE: {state.title}</li>                 <li>CONTENT:???</li>             </ul>         </div>     ) } 
class组件接收参数 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 import React, { Component, useImperativeHandle } from 'react' import { useParams } from "react-router-dom"; // APP.jsx 路由配置 {/* <Route path="/home/messages/detail/:id/:title" element={<Detail></Detail>}></Route> */} // Messages.jsx 列表页面 {/* <Link to={`/home/messages/detail/${item.id}/${item.title}`}>{item.title}</Link> */} function A(props) {     // 获取动态路由的值     const params = useParams();     useImperativeHandle(props.onRef, () => {         return {             params,         }     });     return (         <span></span>     ) } export default class Detail extends Component {     constructor(props) {         super(props);         this.state = {             // 创建ref             funRef: React.createRef(),             data:{}         }     }     paramsData =  ()=> {         let {funRef} = this.state;         this.setState({             data:funRef.current.params         })         console.log(funRef.current.params);     }     render() {         let {funRef,data} = this.state;         return (             <div>                 <ul>                     <li>ID: {data.id}</li>                     <li>TITLE: {data.title}</li>                     <li>CONTENT:???</li>                 </ul>                 <button onClick={this.paramsData}>获取params数据</button>                 <A onRef={funRef} style={{ display: 'none' }}></A>             </div>         )     } } 
push 和 replace 模式 react 默认是push模式 
replace跳转不会形成history,不可返回到上一层this.props.history.replace(‘router地址’) 
push跳转会形成history,可返回到上一层this.props.history.push(‘router地址’) 
 
编程式跳转 函数式组件 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 // v5 import { useHistory } from 'react-router-dom'; function MyButton() {   let history = useHistory();   function handleClick() {     history.push('/home');   };   return <button onClick={handleClick}>Submit</button>; }; // v6 import { useNavigate } from 'react-router-dom'; function MyButton() {   let navigate = useNavigate();   function handleClick() {     navigate('/home');   };   return <button onClick={handleClick}>Submit</button>; }; // v5 history.push('/home'); history.replace('/home'); // v6 navigate('/home'); navigate('/home', {replace: true}); 
1 2 3 4 5 6 7 8 9 10 11 12 13 1. 	import { useNavigate } from 'react-router-dom' 2. 	let navigate = useNavigate(); 	function showReplace(id, title) { 	    // params参数 	    // navigate(`/home/messages/detail/${id}/${title}`,{replace: true}); 	    // search参数 	    navigate(`/home/messages/detail/?id=${id}&title=${title}`,{replace: true}) 	    // navigate state参数 【似乎没有这种方式】 	    // navigate(`/home/messages/detail`, { 'id':id, 'title':title }) 	}; 3.  <button onClick={() => showReplace(item.id, item.title)}>replace查看</button> 
类组件 v5 
1 2 this.props.history.replace(‘router地址’) this.props.history.push(‘router地址’) 
withRouter 【v5有,v6应该是删除了,不能使用】 withRouter:加工一般组件,让一般组件具备路由组件的API,返回值是一个新组件 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 import React, { Component } from 'react' import { withRouter } from 'react-router-dom'  class Header extends Component {     back = () => {         // this.props.history.goBack()     }     // forward = () => {     //     this.props.history.goForward()     // }     // go = () => {     //     this.props.history.go(-2)     // }     render() {         return (                 <div>                     <h2>React Router Demo111</h2>                     <button onClick={this.back}>回退</button>                     <button onClick={this.forward}>前进</button>                     <button onClick={this.go}>go</button>                 </div>         )     } } export default withRouter(Header) 
BrowserRouter 和 HashRouter 的区别 1.底层原理不一样: