本来体验下react-router的,然后
去react-router npm查看,发现了官方的提示如下:
这个包为 React Router 提供了核心路由功能,但你可能不想直接安装它。如果您正在编写将在浏览器中运行的应用程序,您应该安装 react-router-dom。同样,如果您正在编写 React Native 应用程序,则应该安装 react-router-native。这两个都将安装 react-router 作为依赖项
也就是说如果想在react项目中添加路由功能,应该使用react-router-dom而不是react-router,直接使用最新版的react-router可能会报错
既然官方使用react-router-dom替代了react-router,那我们就学习一下怎么使用react-router-dom实现路由功能吧
要在 Web 应用程序中开始使用 React Router,您需要一个 React Web 应用程序。如果您需要创建一个,我们建议您尝试Create React App。这是一个流行的工具,与 React Router 配合得非常好。首先,安装 create-react-app 并用它创建一个新项目
npx create-react-app demo-app
cd demo-app
您可以使用 npm 或 yarn 安装 React Router。由于我们正在构建一个 Web 应用程序,因此我们将在本指南中使用 react-router-dom
npm install react-router-dom
npm run start
接下来,将以下任一示例复制/粘贴到 src/App.js。
import React from "react";
import {
BrowserRouter as Router,
Switch,
Route,
Link
} from "react-router-dom";
export default function App() {
return (
<Router>
<div>
<nav>
<ul>
<li>
<Link to="/">Home</Link>
</li>
<li>
<Link to="/about">About</Link>
</li>
<li>
<Link to="/users">Users</Link>
</li>
</ul>
</nav>
{/* <Switch>标签会渲染将匹配URL的第一个<Route>进行渲染,如果最前面的<Route>匹配了,
后面的就不会渲染,所以对于path="/"的<Route>应该放在最后面,<Switch>相当于js里的switch */}
<Switch>
<Route path="/about">
<About />
</Route>
<Route path="/users">
<Users />
</Route>
<Route path="/">
<Home />
</Route>
</Switch>
</div>
</Router>
);
}
function Home() {
return <h2>Home</h2>;
}
function About() {
return <h2>About</h2>;
}
function Users() {
return <h2>Users</h2>;
}
在这个例子中,我们有 3 个由路由器处理的“页面”:一个主页、一个关于页面和一个用户页面。当您在不同的 <Link> 上点击时,路由器会渲染匹配的 <Route>。
注意:在组件内部,<Link> 会渲染带有真实 href 的 <a>标签,因此人们使用键盘进行导航或屏幕阅读器仍然可以使用这个应用程序。
import React from "react";
import {
BrowserRouter as Router,
Switch,
Route,
Link,
useRouteMatch,
useParams
} from "react-router-dom";
export default function App() {
return (
<Router>
<div>
<ul>
<li>
<Link to="/">Home</Link>
</li>
<li>
<Link to="/about">About</Link>
</li>
<li>
<Link to="/topics">Topics</Link>
</li>
</ul>
<Switch>
<Route path="/about">
<About />
</Route>
<Route path="/topics">
<Topics />
</Route>
<Route path="/">
<Home />
</Route>
</Switch>
</div>
</Router>
);
}
function Home() {
return <h2>Home</h2>;
}
function About() {
return <h2>About</h2>;
}
function Topics() {
let match = useRouteMatch();
return (
<div>
<h2>Topics</h2>
<ul>
<li>
<Link to={`${match.url}/components`}>Components</Link>
</li>
<li>
<Link to={`${match.url}/props-v-state`}>
Props v. State
</Link>
</li>
</ul>
{/* match.path和match.url一直都是"/topics"没变过,所以嵌套路由无非就是
在<Route>里又渲染了一个<Route>,子<Route>需要拼接一下父<Route>的路径match.path
*/}
<Switch>
<Route path={`${match.path}/:topicId`}>
<Topic />
</Route>
<Route path={match.path}>
<h3>Please select a topic.</h3>
</Route>
</Switch>
</div>
);
}
function Topic() {
let { topicId } = useParams();
return <h3>Requested topic ID: {topicId}</h3>;
}
此示例显示嵌套路由的工作原理。路由 /topics 加载 Topics 组件,该组件根据路径 :id 值有条件地渲染任何进一步的 <Route>
希望这些示例能让您了解使用 React Router 创建 Web 应用程序是什么感觉。继续阅读以了解有关 React Router 中主要组件的更多信息!
React Router 中的组件主要分为三类:
路由器,例如 <BrowserRouter> 和 <HashRouter>
路由匹配器,例如 <Route> 和 <Switch>
和导航,例如 <Link>、<NavLink> 和 <Redirect>
我们也喜欢将导航组件视为“路由更改器”。您在 Web 应用程序中使用的所有组件都应该从 react-router-dom 导入。
每个 React Router 应用程序的核心应该是一个路由器组件。对于 web 项目,react-router-dom 提供了 <BrowserRouter> 和 <HashRouter> 路由器。两者之间的主要区别在于它们存储 URL 以及与您的 Web 服务器通信的方式。
<BrowserRouter> 使用常规 URL 路径。这些通常是最好看的 URL,但它们需要正确配置您的服务器。具体来说,您的 Web 服务器需要在由 React Router 客户端管理的所有 URL 上提供相同的页面。 Create React App 在开发中支持开箱即用,并附带有关如何配置生产服务器的说明。
<HashRouter> 将当前位置存储在 URL 的哈希部分中,因此 URL 看起来类似于 http://example.com/#/your/page。由于哈希从未发送到服务器,这意味着不需要特殊的服务器配置。
要使用路由器,只需确保它在元素层次结构的根部渲染。通常,您会将顶级 <App> 元素包装在路由器中,如下所示:
import React from "react";
import ReactDOM from "react-dom";
import { BrowserRouter } from "react-router-dom";
function App() {
return <h1>Hello React Router</h1>;
}
ReactDOM.render(
<BrowserRouter>
<App />
</BrowserRouter>,
document.getElementById("root")
);
有两个路由匹配组件:Switch 和Route。当 <Switch> 被渲染时,它会搜索它的子 <Route> 元素以找到路径与当前 URL 匹配的元素。当它找到一个时,它会渲染那个 <Route> 并忽略所有其他的。这意味着您应该将具有更具体(通常更长)路径的 <Route> 放在不太具体(范围广)的路径之前。如果没有 <Route> 匹配,则 <Switch> 不渲染任何内容(空)。
有时候,同一个路径可以匹配多个路由,此时,匹配的优先级就按照<Route>的排列顺序:<Route>排列得越靠前,优先级就越高。
import React from "react";
import ReactDOM from "react-dom";
import {
BrowserRouter as Router,
Switch,
Route
} from "react-router-dom";
function App() {
return (
<div>
<Switch>
{/* 如果当前URL为/about,则渲染此<Route>
其余的都被忽略了 */}
<Route path="/about">
<About />
</Route>
{/* 注意这两个<Route>是如何排列的。更具体的
path=“/contact/:id”位于path=“/contact”之前,因此
查看单个联系人时将渲染当前<Route> */}
<Route path="/contact/:id">
<Contact />
</Route>
{/* 注意/contact会匹配当前<Route>,而不是上一个*/}
<Route path="/contact">
<AllContacts />
</Route>
{/* 如果之前的任何路径都不渲染任何内容,
这条路径起到了退路的作用。
重要提示:路径为“/”的路由将始终匹配
URL,因为所有URL都以/开头。那就是
为什么我们把这个放在最后,可以当404页面 */}
<Route path="/">
<Home />
</Route>
</Switch>
</div>
);
}
ReactDOM.render(
<Router>
<App />
</Router>,
document.getElementById("root")
);
需要注意的一件重要事情是 <Route path> 匹配 URL 的开头,而不是整个内容。所以 <Route path="/"> 将始终匹配 URL。因此,我们通常将这个 <Route> 放在 <Switch> 的最后。另一种可能的解决方案是使用与整个 URL 匹配的 <Route exact path="/">。
注意:虽然 React Router 确实支持在 <Switch> 之外渲染 <Route> 元素,但从 5.1 版开始,我们建议您改用the useRouteMatch 钩子。此外,我们不建议您在没有路径的情况下渲染 <Route>,而是建议您使用钩子来访问您需要的任何变量。
React Router 提供了一个 <Link> 组件来在你的应用程序中创建链接。无论您在何处渲染 <Link>,都将在您的 HTML 文档中呈现一个锚点 (<a>)。
<NavLink> 是一种特殊类型的 <Link>,当它的 to prop 匹配当前位置时,它可以将自己设置为“活动”。
<Link to="/">Home</Link>
// <a href="/">Home</a>
<NavLink to="/react" activeClassName="hurray">
React
</NavLink>
// 当URL是/react, 它渲染的是:
// <a href="/react" className="hurray">React</a>
// 否则:
// <a href="/react">React</a>
<Redirect to="/login" />
任何时候你想强制导航,你都可以渲染一个 <Redirect>。当 <Redirect> 渲染时,它将使用它的 to prop 进行导航。
React Router 附带了一些钩子,可让您访问路由器的状态并从组件内部执行导航。
请注意:您需要使用 React >= 16.8 才能使用这些钩子中的任何一个, 并且这四个钩子函数只能在<Router>或者被<Router>包裹的子组件里使用,否则就会报错
useHistory
useLocation
useParams
useRouteMatch
useHistory 钩子函数会返回一个history实例,通过这个实例你可以进行跳转操作
import { useHistory } from "react-router-dom";
function HomeButton() {
let history = useHistory();
function handleClick() {
history.push("/home");
}
return (
<button type="button" onClick={handleClick}>
Go home
</button>
);
}
useLocation钩子函数会返回一个location对象,location对象里有当前路径信息,你可以把useLocation想象成useState,当路由改变的时候useLocation都会返回一个最新的地址对象
import React from "react";
import ReactDOM from "react-dom";
import {
BrowserRouter as Router,
Switch,
useLocation
} from "react-router-dom";
function usePageViews() {
let location = useLocation();
React.useEffect(() => {
alert(location.pathname);
}, [location]);
}
function App() {
usePageViews();
return <Switch>...</Switch>;
}
ReactDOM.render(
<Router>
<App />
</Router>,
node
);
useParams会返回URL参数的键/值对象,使用它来访问当前<Route>的match.params
import React from "react";
import ReactDOM from "react-dom";
import {
BrowserRouter as Router,
Switch,
Route,
useParams
} from "react-router-dom";
function BlogPost() {
let { slug } = useParams();
return <div>Now showing post {slug}</div>;
}
ReactDOM.render(
<Router>
<Switch>
<Route exact path="/">
<HomePage />
</Route>
<Route path="/blog/:slug">
<BlogPost />
</Route>
</Switch>
</Router>,
node
);
useRouteMatch 钩子尝试以与 <Route> 相同的方式匹配当前 URL。它对于在不实际渲染 <Route> 的情况下访问匹配数据非常有用
旧的写法:
import { Route } from "react-router-dom";
function BlogPost() {
return (
<Route
path="/blog/:slug"
render={({ match }) => {
// Do whatever you want with the match...
return <div />;
}}
/>
);
}
使用useRouteMatch的写法:
import { useRouteMatch } from "react-router-dom";
function BlogPost() {
let match = useRouteMatch("/blog/:slug");
// Do whatever you want with the match...
return <div />;
}
并且:
如果不传任何参数useRouteMatch会返回当前 <Route> 的匹配对象,就是包裹当前组件的那个<Route>匹配的对象,如果包裹当前组件的是<Routers>,那返回的是path为'/'的匹配对象,不穿传数还不如使用useLocation
或者接受一个参数,它与 matchPath 的 props 参数相同。它可以是字符串形式的路径名(如上面的示例),也可以是具有 Route 接受的匹配道具的对象,如下所示,这个时候如果匹配到了,会返回一个匹配对象,否则会返回null
const match = useRouteMatch({
path: "/BLOG/:slug/",
strict: true,
sensitive: true
});
useRouteMatch可用于条件渲染
参考文档: