反应路由器钩子
React-Router 是一个流行的 React 库,大量用于客户端路由并提供单页路由。它提供了各种组件 API(如 Route、Link、Switch 等),您可以在 React 应用程序中使用这些 API 来根据单个页面中的 URL 路径名呈现不同的组件。
先决条件:如果您还不熟悉 React Router,请先阅读以下文章
- ReactJS 路由器
- ReactJS 类型的路由器
注意:您需要在您的设备中安装 React >= 16.8,否则钩子将不起作用。
React Router 5 的 Hooks: React Router 5 提供了 4 个可以在你的 react 应用程序中使用的 hooks:
- 使用历史
- 使用参数
- 使用位置
- 使用RouteMatch
我们将通过适当的示例详细讨论所有钩子:
1. useHistory:这是 React Router 提供的最流行的钩子之一。它允许您访问 React Router 使用的历史实例。使用历史实例,您可以将用户重定向到另一个页面。 React Router 创建的历史实例使用一个堆栈(称为“历史堆栈”),它存储用户访问过的所有条目。
语法:
import { useHistory } from "react-router-dom";
// Inside a functional component
export default function SomeComponent(props){
// The useHistory() hook returns the history
// object used by React Router
const history = useHistory();
}
useHistory() 返回的历史对象具有各种属性和方法。
特性:
- 长度:返回一个数字。历史堆栈中的条目数
- action:返回表示当前操作(PUSH、REPLACE 或 POP)的字符串。
- location:返回一个表示当前位置的对象。它可能具有以下属性:
- pathname:包含 URL 路径的字符串
- search:包含 URL 查询字符串的字符串
- hash:包含 URL 哈希片段的字符串
- state:一个包含位置特定状态的对象,当这个位置被推入堆栈时,它被提供给例如 push(path, state)。仅在浏览器和内存历史记录中可用。
方法:
- push(path, [state]):将新条目推送到历史堆栈。有助于将用户重定向到页面
- replace(path, [state]):替换历史堆栈上的当前条目
- go(n):将历史堆栈中的指针移动 n 个条目
- goBack():等价于 go(-1)。
- goForward():等价于 go(1)。
- 块(提示):阻止导航。它将回调作为参数,并在导航被阻止后调用它。当您想首先确认用户是否真的想离开页面时最有用。
示例:假设我们有一个使用“create-react-app”创建的 React 项目,具有以下项目结构。
项目结构:
react-router-hooks-tutorial/
|--public/
|--src/
| |--components/
| | |-->Home.js
| | |-->ContactUs.js
| | |-->AboutUs.js
| | |-->LogIn.js
| | |-->Profile.js
| |-->App.js
| |-->App.css
| |-->index.js
| |-->index.css
| |-->... (other files)
|-- ...(other files)
假设在“LogIn.js”中,我们有一个“LogIn”组件来呈现登录页面。 LogIn 组件呈现两个输入字段,一个用于用户名,另一个用于密码。当用户单击登录按钮时,我们要对用户进行身份验证并将用户重定向到他/她的个人资料页面。
LogIn.js
import { useHistory } from "react-router-dom";
import { useState } from "react";
// A function that authenticates the users
function authenticateUser(userName, password) {
// Some code to authenticate the user
}
// Hooks must be used inside a functional component
export default function Login(props) {
//Creating a state variable
const [userName, setUserName] = useState("");
const [password, setPassword] = useState("");
// Accessing the history instance created by React
const history = useHistory();
// Handle the user clicks the login button
const handleClick = () => {
// Authenticate the user
authenticateUser(userName, password);
// When the authentication is done
// Redirect the user to the `/profile/${userName}` page
// the below code adds the `/profile/${userName}` page
// to the history stack.
history.push(`/profile/${userName}`);
};
return (
{
setUserName(e.target.value);
}}
required
/>
{
setPassword(e.target.value);
}}
required
/>
);
}
App.js
import { Route, Switch } from "react-router-dom";
import Home from "./components/Home";
import ContactUs from "./components/ContactUs";
import LogIn from "./components/LogIn";
import AboutUs from "./components/AboutUs";
import Profile from "./components/Profile";
export default function App() {
return (
{/* userName is now a variable */}
);
}
Profile.js
import {useParams} from "react-router-dom";
export default function Profile( props ) {
// useParams() returns an object of the parameters
// defined in the url of the page
// For example, the path given in the Route component
// consists of an "userName" parameter
// in this form ---> "/profile/:userName"
const { userName } = useParams();
return (
Profile of { userName }
This is the profile page of { userName }
);
}
Profile.js
import { useLocation } from "react-router-dom";
export default function Profile(props) {
const location = useLocation();
// location.search returns a string containing all
// the query parameters.
// Suppose the URL is "some-website.com/profile?id=12454812"
// then location.search contains "?id=12454812"
// Now you can use the URLSearchParams API so that you can
// extract the query params and their values
const searchParams = new URLSearchParams(location.search);
return (
{
// Do something depending on the id value
searchParams.get("id") // returns "12454812"
}
);
}
Profile.js
import { Link, Route, useParams, useRouteMatch } from "react-router-dom";
export default function Profile(props) {
// useParams() returns an object of the parameters
// defined in the url of the page
// For example, the path given in the Route component
// consists of an "userName" parameter
// in this form ---> "/profile/:userName"
const { userName } = useParams();
const match = useRouteMatch();
return (
{match.isExact ? (
Profile of {userName}
This is the profile page of {userName}
Followers
) : (
My followers
)}
);
}
About.js
import {useLocation} from "react-router-dom";
export default function ( props ){
// Accessing the location and history
// through the props
const location = props.location;
const history = props.history;
return(
// Some content
);
}
App.js
import "./styles.css";
import { Route, Switch } from "react-router-dom";
import About from "./components/About";
export default function App() {
return (
// In this case, you have to use render
// instead of component and explicitly
// pass the props
(
)}
/>
);
}
App.js
import "./styles.css";
import { Route, Switch } from "react-router-dom";
import Home from "./components/Home";
import ContactUs from "./components/ContactUs";
import LogIn from "./components/LogIn";
import AboutUs from "./components/AboutUs";
export default function App() {
return (
);
}
Home.js
import {
useHistory,
useLocation,
useParams,
useRouteMatch,
} from "react-router-dom";
export default function Home(props) {
// Access the history object with useHistory()
const history = useHistory();
// Access the location object with useLocation
const location = useLocation();
// Access the match object with useRouteMatch
const match = useRouteMatch();
// Extract the URL parameters with useParams
const params = useParams();
return {/* Some code */};
}
输出:
仔细检查 Login 组件,“ handleClick ”函数获取用户名和密码并调用“ authenticateUser ”函数以某种方式对用户进行身份验证。验证完成后,我们希望将用户重定向到“profile/John”(假设用户名是“John”)页面。这就是handleClick函数的最后一行所做的。 “useHistory()”钩子返回由 React Router 创建的历史实例,history.push(“/profile/John”) 将给定的 URL 添加到历史堆栈,从而将用户重定向到给定的 URL 路径。同样,您可以根据需要使用历史对象的其他方法和参数。
检查下一个钩子以了解重定向到动态 URL 的工作原理。
2. useParams:这个钩子返回一个由URL中所有参数组成的对象。
句法:
import { useParams } from "react-router-dom";
// Inside a functional component
export default function SomeComponent(props){
const params = useParams();
}
这些 URL 参数在路由 URL 中定义。例如,
“/profile/”后面的冒号(“:”)表示“userName”实际上是一个动态的变量或参数。例如,在url“/profile/johndoe”中,“johndoe”是参数“userName”的值。因此,在这种情况下,useParams() 返回的对象是:
{
userName: "johndoe"
}
示例:登录后,我们希望我们的用户被重定向到“profile/userName” URL。 userName 取决于用户的名字。因此,我们需要根据用户给定的 userName 动态设置 URL 路径。这很容易做到,我们需要稍微更新一下 App.js 文件。
应用程序.js
import { Route, Switch } from "react-router-dom";
import Home from "./components/Home";
import ContactUs from "./components/ContactUs";
import LogIn from "./components/LogIn";
import AboutUs from "./components/AboutUs";
import Profile from "./components/Profile";
export default function App() {
return (
{/* userName is now a variable */}
);
}
Profile.js
import {useParams} from "react-router-dom";
export default function Profile( props ) {
// useParams() returns an object of the parameters
// defined in the url of the page
// For example, the path given in the Route component
// consists of an "userName" parameter
// in this form ---> "/profile/:userName"
const { userName } = useParams();
return (
Profile of { userName }
This is the profile page of { userName }
);
}
输出:现在,如果您现在转到登录页面并单击用户名“John”的登录按钮,那么您将被重定向到“profile/john”页面。
3. useLocation:这个钩子返回react-router使用的位置对象。此对象表示当前 URL,并且是不可变的。每当 URL 更改时,useLocation() 钩子都会返回一个新更新的位置对象。它的一些用途包括从 URL 中提取查询参数并根据查询参数执行某些操作。位置对象的“搜索”属性返回一个包含 URL 查询部分的字符串。
句法 :
import { useLocation } from "react-router-dom";
// Inside functional component
export default function SomeComponent(props){
const location = useLocation();
}
注意: history.location 也代表当前位置,但它是可变的,另一方面,useLocation() 返回的位置是不可变的。所以,如果你想使用位置实例,推荐使用 useLocation() 钩子。
示例: useLocation() 对于获取和使用 URL 中定义的查询参数非常有用。在下面的代码中,我们使用了 useLocation 挂钩来访问查询参数。然后我们使用 URLSearchParams 构造函数解析它。
Profile.js
import { useLocation } from "react-router-dom";
export default function Profile(props) {
const location = useLocation();
// location.search returns a string containing all
// the query parameters.
// Suppose the URL is "some-website.com/profile?id=12454812"
// then location.search contains "?id=12454812"
// Now you can use the URLSearchParams API so that you can
// extract the query params and their values
const searchParams = new URLSearchParams(location.search);
return (
{
// Do something depending on the id value
searchParams.get("id") // returns "12454812"
}
);
}
输出 :
4. useRouteMatch:返回一个匹配对象,其中包含当前URL如何与Route路径匹配等所有信息。
特性:
- params:这是一个包含 URL 可变部分的对象。
- isExact:这是一个布尔值,指示整个 URL 是否与给定的路由器路径匹配。
- path:包含路径模式的字符串。
- URL:包含 URL 匹配部分的字符串。它可以用于嵌套的 和
。
句法 :
import { useRouteMatch } from "react-router-dom";
// Inside functional component
export default function SomeComponent(props) {
const match = useRouteMatch();
}
示例: useRouterMatch 挂钩可用于创建嵌套路由和链接。以下代码在当前 URL 路径与给定 Route 路径完全匹配时呈现用户的 Profile 页面,否则,当当前 URL 路径为“profile/:userName/followers”时,它会呈现另一个呈现用户关注者页面的 Route。
Profile.js
import { Link, Route, useParams, useRouteMatch } from "react-router-dom";
export default function Profile(props) {
// useParams() returns an object of the parameters
// defined in the url of the page
// For example, the path given in the Route component
// consists of an "userName" parameter
// in this form ---> "/profile/:userName"
const { userName } = useParams();
const match = useRouteMatch();
return (
{match.isExact ? (
Profile of {userName}
This is the profile page of {userName}
Followers
) : (
My followers
)}
);
}
输出:
如果您单击关注者的链接,您将被重定向到“/profile/John/followers”页面,并且由于整个 URL 路径“profile/John/followers”与给定的 Route 路径(即“profile/;userName”)不匹配,因此 Route 组件内的 div 元素被渲染。
请记住,您需要拥有 React 16.8 或更高版本才能使用这些 react-router 挂钩。另外,不要忘记在功能组件中使用它们。
使用 React Router Hooks 的原因
在 React Router 5 之前:默认情况下,在使用组件 prop (
关于.js
import {useLocation} from "react-router-dom";
export default function ( props ){
// Accessing the location and history
// through the props
const location = props.location;
const history = props.history;
return(
// Some content
);
}
但是,如果您将自定义道具传递给您的组件,那么默认道具将被您的自定义道具覆盖。因此,您将无法进一步访问由 React Router 创建的历史对象。在 React Router 5 之前,除了使用 render prop (
应用程序.js
import "./styles.css";
import { Route, Switch } from "react-router-dom";
import About from "./components/About";
export default function App() {
return (
// In this case, you have to use render
// instead of component and explicitly
// pass the props
(
)}
/>
);
}
使用 React Router 5 Hooks:现在使用 React Router 5,您可以轻松地将自定义道具传递给渲染组件。
应用程序.js
import "./styles.css";
import { Route, Switch } from "react-router-dom";
import Home from "./components/Home";
import ContactUs from "./components/ContactUs";
import LogIn from "./components/LogIn";
import AboutUs from "./components/AboutUs";
export default function App() {
return (
);
}
虽然在这种情况下,这三个 props(match、location、history)也不会自动通过渲染的组件,但我们现在可以使用 React Router 5 提供的 hooks,我们不再需要考虑 props。您可以使用 useHistory 钩子直接访问历史对象,使用 useLocation 钩子的 location 对象,以及使用 useRouteMatch 钩子匹配对象,您不必显式地将 props 传递给组件。
主页.js
import {
useHistory,
useLocation,
useParams,
useRouteMatch,
} from "react-router-dom";
export default function Home(props) {
// Access the history object with useHistory()
const history = useHistory();
// Access the location object with useLocation
const location = useLocation();
// Access the match object with useRouteMatch
const match = useRouteMatch();
// Extract the URL parameters with useParams
const params = useParams();
return {/* Some code */};
}