📜  反应路由器钩子

📅  最后修改于: 2022-05-13 01:56:23.984000             🧑  作者: Mango

反应路由器钩子

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"       }     
  ); }

输出 :

显示给定的查询 id

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 () 时,React 路由器将三个 props(match, location, history) 传递给 Route 渲染的组件。这意味着,如果您出于某种原因想要访问 React 路由器使用的历史记录或位置实例,您可以通过默认道具访问它。

关于.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 () 将位置、匹配和历史实例作为 props 显式传递之外,别无他法。

应用程序.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 */}
; }