react-router-dom5.x使用示例
- 微信扫码关注公众号 :前端前端大前端,追求更精致的阅读体验 ,一起来学习啊
- 关注后发送关键资料,免费获取一整套前端系统学习资料和老男孩python系列课程
安装
npm install --save react-router-dom
使用
import React from 'react';
import { BrowserRouter as Router, Route, Link } from "react-router-dom";
import Home from './components/Home'
import News from './components/News'
import Music from './components/Music'
//exact表示严格匹配,去掉的话,访问/news实际会渲染Home,News两个组件
function App() {
return (
<Router>
<Route exact path="/" component={Home} />
<Route path="/news" component={News} />
<Route path="/music" component={Music} />
</Router>
);
}
export default App;
Link的使用
类似vue的vue-router,实际每个Link默认被渲染为a标签
<Link to='/' > 首页</Link>
<Link to='/news'>新闻</Link>
<Link to='/music'>音乐</Link>
BasicExample–基础实例
分析
这是一个最基础的路由示例,根据不同的url渲染不同的组件。值得注意的是,对于Route组件而言,支持的渲染组件方式
不唯一
。单标签
的时候可以使用component
属性,render
属性,或者children
属性挂载要渲染的组件。双标签
的时候包裹要渲染的组件,也就是children…
import React from 'react'
import {
BrowserRouter as Router,
Switch,
Route,
Link
} from "react-router-dom";
const Home = () => <h2>Home</h2>
const About = () => <h2>About</h2>
const Dashboard = () => <h2>Dashboard</h2>
const News = () => <h2>News</h2>
const Games = () => <h2>Games</h2>
export default function () {
return (
<Router>
<div>
<ul>
<li> <Link to="/">Home</Link> </li>
<li> <Link to="/about">About</Link> </li>
<li> <Link to="/dashboard">Dashboard</Link> </li>
<li> <Link to="/news">News</Link> </li>
<li> <Link to="/games">Games</Link> </li>
</ul>
<hr />
<Switch>
<Route exact path="/"> <Home /></Route>
<Route path="/about" component={About} />
<Route path="/dashboard" children={<Dashboard />} />
<Route path="/news" render={()=><News />} />
<Route path="/games" component={()=><Games/>} />
</Switch>
</div>
</Router>
);
}
UrlParams–动态路由
分析
该示例演示了动态路由是如何匹配的,以及如何获取匹配到的参数值。和很多框架匹配规则一致,都是
:param
.在获取参数的时候,可以用hooks形式 ,也可以用原始的props.match.params.xxx
import React from "react";
import {
BrowserRouter as Router,
Switch,
Route,
Link,
useParams
} from "react-router-dom";
export default function () {
return (
<Router>
<div>
<h2>Accounts</h2>
<ul>
<li>
<Link to="/netflix/1">Netflix</Link>
</li>
<li>
<Link to="/zillow-group/2">Zillow Group</Link>
</li>
<li>
<Link to="/yahoo/3">Yahoo</Link>
</li>
<li>
<Link to="/modus-create/4">Modus Create</Link>
</li>
</ul>
<Switch>
<Route path="/:page/:num" component={Child} />
</Switch>
</div>
</Router>
);
}
function Child(props) {
let { page} = useParams();
let num=props.match.params.num;
return (
<div>
<h3>
当前页: {page}--数字:{num}
</h3>
</div>
);
}
Nesting–嵌套路由
分析
嵌套路由适用于有明显层级划分的情况,以官方示例来看,主层级分为home和topics,topics又划分出三个子主题,这就涉及到了嵌套路由。子路由的url都是在父级路由基础上拼接出来的。
像这样 /topics /topics/rendering
。值得注意的是,这个案例里用到了一个新的hooks,useRouteMatch
,这就相当于原始的props.match
.此外,这个示例里对useRouteMatch()解构了path和url,如果你打印一下,你会发现它们的值是一样的,也许就像原文解释那样,一个用来获取父路径,一个用于Link组件的跳转,更规范?
import React from "react";
import {
BrowserRouter as Router,
Switch,
Route,
Link,
useParams,
useRouteMatch
} from "react-router-dom";
const Home = () => <h2>Home</h2>
const Topic = () => {
let { topicId } = useParams();
return <h3>{topicId}</h3>
}
const Topics = () => {
let { path, url } = useRouteMatch();
return (
<div>
<h2>Topics</h2>
<ul>
<li><Link to={`${url}/rendering`}>Rendering with React</Link></li>
<li><Link to={`${url}/components`}>Components</Link></li>
<li><Link to={`${url}/props-v-state`}>Props v. State</Link></li>
</ul>
<Switch>
<Route exact path={path}> <h3>Please select a topic.</h3></Route>
<Route path={`${path}/:topicId`} component={Topic} />
</Switch>
</div>
);
}
export default function () {
return (
<Router>
<div>
<ul>
<li><Link to="/">Home</Link></li>
<li><Link to="/topics">Topics</Link></li>
</ul>
<hr />
<Switch>
<Route exact path="/" component={Home} />
<Route path="/topics" component={Topics} />
</Switch>
</div>
</Router>
);
}
AuthRoute–路由鉴权
分析
这是一个简化后的改写demo.核心是通过
高阶组件
+状态控制
实现路由鉴权。在实际开发中,有些页面必须登录才可以访问,甚至不同身份的人看到的页面也是不一样的。public
页面都可以访问,protected
页面必须登录才可以访问。登录状态这里使用一个变量isLogin
控制.Redirect 组件用于身份验证不通过时重定向处理,useHistory 钩子函数可获取历史记录接口,控制页面跳转。PrivateRoute 是一个高阶组件,对基础的Route进行了进一步封装,注意...rest,在这里相当于将高阶组件获取的path属性传递给Route
import React from "react";
import {
BrowserRouter as Router,
Switch,
Route,
Link,
Redirect,
useHistory,
} from "react-router-dom";
let isLogin = false;
const LoginBtn = () => <button onClick={()=>{isLogin = true}}>登录</button>
const LoginOutBtn = () => {
let history=useHistory();
return <button onClick={()=>{isLogin = false;history.push("/login")}}>退出登录</button>
}
const Login = () => <LoginBtn/>
const Condition = ({ children }) => isLogin ? children : <Redirect to="/login" />
const PrivateRoute = ({ children, ...rest }) => {
return (
<Route {...rest} render={() => <Condition children={children} />} />
);
}
export default function () {
return (
<Router>
<p><Link to={"/public"} >public</Link></p>
<p><Link to={"/protected"}>protected</Link></p>
<Switch>
<Route exact path="/" render={() => <h3>home</h3>} />
<Route path="/public" render={() => <h3>public</h3>} />
<Route path="/login" component={Login} />
<PrivateRoute path="/protected">
<h2>已经登录 可查看-protected</h2>
<LoginOutBtn/>
</PrivateRoute>
</Switch>
</Router>
)
}
CustomLink–自定义路由
分析
自定义路由本质是在Route组件的基础上加入了一些定制化处理,相当于包裹了一层。为了更好理解,这里对官方示例做了个微调,强匹配属性exact直接写入而不是传参形式体现。
useRouteMatch
可以根据path
返回一个匹配结果对象,exact
表示强匹配
,借助于Route
组件,useRouteMatch可以空调用,像这样useRouteMatch()
.反之,需要传参。可参考上一篇中的嵌套路由,对比查看。
import React from "react";
import {
BrowserRouter as Router,
Switch,
Route,
Link,
useRouteMatch
} from "react-router-dom";
const Home = () => <h2>Home</h2>
const About = () => <h2>About</h2>
export default function () {
return (
<Router>
<div>
<MyLink to="/" label="Home" />
<MyLink to="/about" label="About" />
<hr />
<Switch>
<Route exact path="/" component={Home} />
<Route path="/about" component={About} />
</Switch>
</div>
</Router>
);
}
function MyLink({ label, to }) {
let match = useRouteMatch({
path: to,
exact: true
})
// 这里返回的match对象仅用于样式控制
return (
<div className={match ? "active" : ""}>
{match && "> "}
<Link to={to}>{label}</Link>
</div>
);
}
PreventingTransitions–阻止过渡
分析
正常情况下,在用户在表单中填写了一些信息但是没提交的情况下,点击其他页面跳转链接,等再返回的时候,表单数据会丢失。这个例子就是提供一种阻断方式,在进行页面跳转的时候给用户一个提示,确认后会跳转,避免因为误操作导致的表单数据丢失。提示这里使用的是
Prompt
组件,when
属性为一个布尔值,true
弹出提示框,message
为具体的提示信息。Prompt
也可以写在form
之外,保证在要渲染的组件里即可。这种场景,通常用于长表单输入,比如注册。关于Prompt,还有个好用的点,下边单独介绍。
import React, { useState } from "react";
import {
BrowserRouter as Router,
Switch,
Route,
Link,
Prompt
} from "react-router-dom";
// Sometimes you want to prevent the user from
// navigating away from a page. The most common
// use case is when they have entered some data
// into a form but haven't submitted it yet, and
// you don't want them to lose it.
export default function PreventingTransitionsExample() {
return (
<Router>
<ul>
<li>
<Link to="/">Form</Link>
</li>
<li>
<Link to="/one">One</Link>
</li>
<li>
<Link to="/two">Two</Link>
</li>
</ul>
<Switch>
<Route path="/" exact children={<BlockingForm />} />
<Route path="/one" children={<h3>One</h3>} />
<Route path="/two" children={<h3>Two</h3>} />
</Switch>
</Router>
);
}
function BlockingForm() {
let [isBlocking, setIsBlocking] = useState(false);
return (
<form
onSubmit={event => {
event.preventDefault();
event.target.reset();
setIsBlocking(false);
}}
>
<Prompt
when={isBlocking}
message={location =>
`Are you sure you want to go to ${location.pathname}`
}
/>
<p>
Blocking?{" "}
{isBlocking ? "Yes, click a link or the back button" : "Nope"}
</p>
<p>
<input
size="50"
placeholder="type something to block transitions"
onChange={event => {
setIsBlocking(event.target.value.length > 0);
}}
/>
</p>
<p>
<button>Submit to stop blocking</button>
</p>
</form>
);
}
Prompt
- message属性还可以接收一个函数,该函数可以获取到下一个位置(location),返回true不提示,反之,弹出提示
<Prompt
message={location =>
location.pathname.startsWith("/one")
? true
: `Are you sure you want to go to ${location.pathname}?`
}
/>
NO Match–404
分析
该示例演示的是对404的处理,用于捕获所有未匹配的项,通常放置于Switch的最后一项Route里,匹配规则为*。当然,也许你还想将所有的未捕获页面都跳转到
/error
,这个需要使用重定向,后边会介绍
import React from "react";
import {
BrowserRouter as Router,
Route,
Link,
Switch,
Redirect,
useLocation
} from "react-router-dom";
export default function NoMatchExample() {
return (
<Router>
<div>
<ul>
<li>
<Link to="/">Home</Link>
</li>
<li>
<Link to="/old-match">Old Match, to be redirected</Link>
</li>
<li>
<Link to="/will-match">Will Match</Link>
</li>
<li>
<Link to="/will-not-match">Will Not Match</Link>
</li>
<li>
<Link to="/also/will/not/match">Also Will Not Match</Link>
</li>
</ul>
<Switch>
<Route path="*" >
<NoMatch />
</Route>
<Route exact path="/">
<Home />
</Route>
<Route path="/old-match">
<Redirect to="/will-match" />
</Route>
<Route path="/will-match">
<WillMatch />
</Route>
</Switch>
</div>
</Router>
);
}
function Home() {
return <h3>Home</h3>;
}
function WillMatch() {
return <h3>Matched!</h3>;
}
function NoMatch() {
let location = useLocation();
return (
<div>
<h3>
No match for <code>{location.pathname}</code>
</h3>
</div>
);
}
统一处理404
代码看起来像这样,如此一来,所有的404都会统一跳转到
/error
<Switch>
<Route path="/one" component={One}/>
<Route path="/two" component={Two}/>
<Route path="/error" component={Error}/>
<Redirect from="/*" to="/error" />
</Switch>
Sidebar 侧边栏
分析
侧边栏这个案例很常见,官方示例里边介绍的除了基础侧边栏,还扩展了一种多处渲染的方式。即当路由匹配到当前url时,可以在应用给程序内任何你想渲染的地方去分别渲染sideber和main,注意下边的map遍历,只有children属性那里有差异
import React from "react";
import {render} from "react-dom";
import {
BrowserRouter as Router,
Switch,
Route,
Link
} from "react-router-dom";
const routes = [
{
path: "/",
exact: true,
sidebar: () => <div>home!</div>,
main: () => <h2>Home</h2>
},
{
path: "/bubblegum",
sidebar: () => <div>bubblegum!</div>,
main: () => <h2>Bubblegum</h2>
},
{
path: "/shoelaces",
sidebar: () => <div>shoelaces!</div>,
main: () => <h2>Shoelaces</h2>
}
];
export default function SidebarExample() {
return (
<Router>
<div style={{ display: "flex" }}>
<div
style={{
padding: "10px",
width: "40%",
background: "#f0f0f0"
}}
>
<ul style={{ listStyleType: "none", padding: 0 }}>
<li>
<Link to="/">Home</Link>
</li>
<li>
<Link to="/bubblegum">Bubblegum</Link>
</li>
<li>
<Link to="/shoelaces">Shoelaces</Link>
</li>
</ul>
<Switch>
{routes.map((route, index) => (
<Route
key={index}
path={route.path}
exact={route.exact}
children={<route.sidebar />}
/>
))}
</Switch>
</div>
<div style={{ flex: 1, padding: "10px" }}>
<Switch>
{routes.map((route, index) => (
<Route
key={index}
path={route.path}
exact={route.exact}
children={<route.main />}
/>
))}
</Switch>
</div>
</div>
</Router>
);
}
render(<SidebarExample/>,document.getElementById("root"))
效果图
- 结合效果图来看,侧边栏底部和右侧,都进行了渲染,即多处渲染。注意,这两次其实除了渲染的组件不同,其他都一样
config 路由配置
分析
有时候,也许你希望将路由集中配置,比如放在一个数组里,每个路由对象包含path和component。涉及嵌套的,就再来一个数组,存放子路由对象。
import React from "react";
import { render } from 'react-dom'
import {
BrowserRouter as Router,
Switch,
Route,
Link
} from "react-router-dom";
const Sandwiches = () => <h2>Sandwiches</h2>
const Bus = () => <h2>Bus</h2>
const Cart = () => <h2>Cart</h2>
const routes = [
{
path: "/sandwiches",
component: Sandwiches
},
{
path: "/tacos",
component: Tacos,
routes: [
{
path: "/tacos/bus",
component: Bus
},
{
path: "/tacos/cart",
component: Cart
}
]
}
];
export default function App() {
return (
<Router>
<div>
<ul>
<li>
<Link to="/tacos">Tacos</Link>
</li>
<li>
<Link to="/sandwiches">Sandwiches</Link>
</li>
</ul>
<Switch>
{routes.map((route, i) => (
<RouteWithSubRoutes key={i} {...route} />
))}
</Switch>
</div>
</Router>
);
}
function RouteWithSubRoutes(route) {
return (
<Route
path={route.path}
render={(props) => {
return <route.component {...props} routes={route.routes} />
}}
/>
);
}
function Tacos({ routes }) {
return (
<div>
<h2>Tacos</h2>
<ul>
<li>
<Link to="/tacos/bus">Bus</Link>
</li>
<li>
<Link to="/tacos/cart">Cart</Link>
</li>
</ul>
<Switch>
{routes.map((route, i) => (
<RouteWithSubRoutes key={i} {...route} />
))}
</Switch>
</div>
);
}
render(<App />, document.getElementById("root"))
Query parameters 查询参数
分析
该示例其实本质是借用了浏览器内置的URLSearchParams,这个方法可以很方便的解析url参数,但这个存在兼容问题,放弃IE家族就没问题了。具体URLSearchParamsAPI,可参考MDN这段示例代码:
var paramsString = "q=URLUtils.searchParams&topic=api"
var searchParams = new URLSearchParams(paramsString);
searchParams.has("topic") === true; // true
searchParams.get("topic") === "api"; // true
searchParams.getAll("topic"); // ["api"]
searchParams.get("foo") === null; // true
searchParams.append("topic", "webdev");
searchParams.toString(); // "q=URLUtils.searchParams&topic=api&topic=webdev"
searchParams.set("topic", "More webdev");
searchParams.toString(); // "q=URLUtils.searchParams&topic=More+webdev"
searchParams.delete("topic");
searchParams.toString(); // "q=URLUtils.searchParams"
import React from "react";
import { render } from 'react-dom'
import {
BrowserRouter as Router,
Link,
useLocation
} from "react-router-dom";
export default function App() {
return (
<Router>
<QueryParamsDemo />
</Router>
);
}
//这里是重点
function useQuery() {
return new URLSearchParams(useLocation().search);
}
function QueryParamsDemo() {
let query = useQuery();
return (
<div>
<div>
<h2>Accounts</h2>
<ul>
<li>
<Link to="/account?name=netflix">Netflix</Link>
</li>
<li>
<Link to="/account?name=zillow-group">Zillow Group</Link>
</li>
<li>
<Link to="/account?name=yahoo">Yahoo</Link>
</li>
<li>
<Link to="/account?name=modus-create">Modus Create</Link>
</li>
</ul>
<Child name={query.get("name")} />
</div>
</div>
);
}
function Child({ name }) {
return (
<div>
{name ? (
<h3>
The <code>name</code> in the query string is "{name}
"
</h3>
) : (
<h3>There is no name in the query string</h3>
)}
</div>
);
}
render(<App />, document.getElementById("root"))
来源:CSDN
作者:_冷月心
链接:https://blog.csdn.net/qq_42813491/article/details/103652111