目录
react 导入 react-router-dom引入Switch报 ‘Switch‘ is not exported from ‘react-router-dom‘
React路由:React-Router
官网文档
https://reactrouter.com/web/guides/quick-start
React路由基础
1. 安装依赖:`cnpm install --save react-router-dom`
2. 路由配置:
import { BrowserRouter as Router,Route } from "react-router-dom"
<Router>
<Route path="/about" component={ About }></Route>
<Route path="/home" component={ Home }></Route>
</Router>
在使用router的时候可能会有这样的错误
A <Route> is only ever to be used as the child of <Routes> element, never rendered directly. Please wrap your <Route> in a <Routes>.
这是因为在 React-Router v6
版本中,Route更改了使用方式。
使用 Route 需要在 Routes 标签包裹下:
import { BrowserRouter, Link, Route, Routes } from "react-router-dom"
import Home from './components/Home/Home'
import About from './components/About/About'
<Routes>
<Route path="/home" element={<Home />} />
<Route path="/about" element={<About />} />
</Routes>
在 V5 版本则是这样使用:
import { BrowserRouter, Link, Route, Switch } from "react-router-dom"
import Home from './components/Home/Home'
import About from './components/About/About'
<Switch>
<Route path="/home" component={Home} />
<Route path="/about" component={About} />
</Switch>
也可以降低版本 $ cnpm i react-router-dom@5.2.0
HashRouter和BrowserRouter的区别
1. 表现上的区别
HashRouter:/#/path
BrowserRouter:/path
在生产环境中,一定需要后台配合,如果我们直接访问某一个子地址,会出现404问题,后台需要做重定向
2. 实现上的区别(原理最基本的点)
HashRouter:锚点 <a href="#/about"></a>
BrowserRouter:H5新特性,History.pushState()方法
Link跳转
1. 跳转:link -> to:跳转的路径
2. Link:在浏览器中,最终渲染成a标签
exact和strict严格模式匹配
exact:严格模式匹配
strict:具体路径 /,使用之前,必须先添加exact
Switch(V6弃用)和404页面
Switch:当前页面匹配,只匹配一个
NotFound:404页面匹配
react 导入 react-router-dom引入Switch报 ‘Switch‘ is not exported from ‘react-router-dom‘
这是因为react-router-dom从V5升级到V6后,有些使用做了一些改变:
1) Switch 重命名为 Routes
2) Route 的新特性变更 ,component/render被element替代
3) 嵌套路由变得更简单
具体变化有以下:
- Route children 已更改为接受子路由。
- 比Route exact 和 Route strict更简单的匹配规则。
- Route path 路径层次更清晰。
新API:Outlet 多个 Routes
4) 用 useNavigate 代替 useHistory
5) 新钩子 useRoutes 代替 react-router-config
6) 大小减少:从20kb到8kb
详情https://blog.csdn.net/weixin_40906515/article/details/104957712
NavLink高亮处理
NavLink
activeStyle
activeClassName
React does not recognize the `activeClassName` prop on a DOM element. If you intentionally want it to appear in the DOM as a custom attribute, spell it as lowercase `activeclassname` instead. If you accidentally passed it from a parent component, remove it from the DOM element.
在V6版本react-router-dom中取消了activeClassName属性!!淦!
<div>
{/* react-router-dom v5的实现方式 */}
{/* <NavLink activeClassName="activeCls" className="list-item" {...this.props}/> */}
{/* react-router-dom v6的实现方式 */}
<NavLink className={({ isActive }) => "list-item" + (isActive ? " activeCls" : "")} {...this.props} />
</div>
路由跳转携带参数
1. 常规传递参数方式(restfull API)
1. 在路由配置页面增加key:`<Route path="/details/:id" component={ Details }></Route>`
2. 在页面跳转的部分传递参数:`<Link to={`/details/${ ele.id }`}>{ ele.title }</Link>`
3. 对应页面读取参数:`this.props.match.params.id`
2. queryString
1. 跳转携带参数:`<li><NavLink to="/query?name=iwen">参数</NavLink></li>`
2. 读取数据:
1. 安装依赖:`npm install --save query-string`
2. 读取数据:`const { name } = qs.parse(this.props.location.search);`
params参数传递:
v5版本:
//路由链接(携带参数):
<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版本:
//路由链接(携带参数):
<Link to={{ pathname:`/b/child1/${id}/${title}` }}>Child1</Link>
//或 <Link to={`/b/child1/${id}/${title}`}>Child1</Link>
//注册路由(声明接收):
<Route path="/b/child1/:id/:title" element={<Test/ >} />
//接收参数:接收参数的组件一定要是函数式声明的(class不可以)!!!
import { useParams } from "react-router-dom";
const params = useParams();
//params参数 => {id: "01", title: "消息1"}
search参数:
v5版本:
//路由链接(携带参数):
<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版本:
//路由链接(携带参数):
<Link className="nav" to={`/b/child2?age=20&name=zhangsan`}>Child2</Link>
//注册路由(无需声明,正常注册即可):
<Route path="/b/child2" component={Test}/>
//接收参数方法1:接收参数的组件一定要是函数式声明的(class不可以)!!!
import { useLocation } from "react-router-dom";
import { qs } from "url-parse";
const { search } = useLocation();
const searchs = qs.parse(search)
//search参数 => {age: "20", name: "zhangsan"}
//接收参数方法2:接收参数的组件一定要是函数式声明的(class不可以)!!!
import { useSearchParams } from "react-router-dom";
const [searchParams, setSearchParams] = useSearchParams();
// console.log( searchParams.get("id")); // 12
//备注:获取到的search是urlencoded编码字符串(例如: ?age=20&name=zhangsan),需要借助 url-parse 里面的 qs.parse 解析参数成对象
路由重定向
Navigate代替Redirect
import React, { Component } from 'react'
import { BrowserRouter as Router, HashRouter, Route, Routes,Navigate } from 'react-router-dom'
import Home from '../views/Home'
import About from '../views/About'
import News from '../views/News'
import NotFound from "../views/NotFound"
import NavLink from '../components/NavMain'
export default class Layout extends Component {
render() {
return (
<HashRouter>
<NavLink />
<Routes>
<Route path='/home' element={<Home />}></Route>
<Route path="/" element={<Navigate replace to="/home" />} />
{/* <Route path='/about' element={<News />}></Route>使用Routes 只匹配第一个/about */}
<Route path='/about' element={<About />}></Route>
<Route path='/news' element={<News />}></Route>
<Route path="*" element={ <NotFound /> }></Route>
</Routes>
</HashRouter>
)
}
}
import React, { Component } from 'react'
import { Link, NavLink } from 'react-router-dom'
import './style.css'
export default class NavMain extends Component {
render() {
return (
<div className="nav">
<ul>
{/* <li><NavLink activeClassName="selected" exact strict to="/">首页</NavLink></li>
<li><NavLink activeClassName="selected" exact to="/about">关于</NavLink></li> */}
{/* <li><NavLink activeClassName="selected" exact to="/news">新闻</NavLink> */}
<li><NavLink className={({ isActive }) => "active" + (isActive ? " selected" : "")} {...this.props} to="/news">新闻</NavLink></li>
<li><NavLink className={({ isActive }) => "active" + (isActive ? " selected" : "")} {...this.props} to="/about">关于</NavLink></li>
<li><NavLink className={({ isActive }) => "active" + (isActive ? " selected" : "")} {...this.props} to="/home" exact='true'>首页</NavLink></li>
{/* exact='true' 没效果?*/}
{/* </li> */}
</ul>
</div>
)
}
}
编程式导航
v5:
1. push:this.props.history.push("/about")
可以返回到上一个页面(堆栈里是有缓存的)
2. repace:this.props.history.replace("/about")
不可以返回到上一个页面,上一个页面已经被新的页面替换了(完全替换,堆栈里不再有上一个页面的缓存)
v6:
// v6版本编程导航使用 useNavigate
import { useNavigate } from "react-router-dom";
export default function A() {
const navigate = useNavigate();
//...
}
push跳转携带params参数
navigate(`/b/child1/${id}/${title}`);
push跳转携带search参数
navigate(`/b/child2?id=${id}&title=${title}`);
push跳转携带state参数
navigate("/b/child2", { state: { id, title }});
前进
<button onClick={() => navigate(1)}>Go Forword</button>
后退
<button onClick={() => navigate(-1)}>Go back</button>
前进或后退几步
<button onClick={() => navigate(2)}>Go</button>
replace跳转携带params参数
navigate(`/b/child1/${id}/${title}`,{replace: true});
replace跳转携带search参数
navigate(`/b/child2?id=${id}&title=${title}`,{replace: true});
replace跳转携带state参数
navigate("/b/child2", { state: { id, title },replace: true});
withRouter(v6版本弃用)
路由的高阶组件:让没有被路由所直接管理的组件具有路由对象,history对象
使用 useNavigate 即可
路由嵌套
V5:
1. 作为上一级路由的子元素
```
<User path="/user">
<Redirect from="/user" to="/user/info"></Redirect>
<Route path="/user/info" component={ UserInfo }></Route>
<Route path="/user/order" component={ UserOrder }></Route>
</User>
```
2. 在父级视图中,要给子视图显示的空间
`{ this.props.children }`
React6文档
我看视频学的是V5,写代码用的V6,有点难受......,接下来学习Redux状态管理