React 之 Router - 路由详解

一、Router的基本使用

1. 安装react-router

react-router会包含一些react-native的内容,web开发并不需要

npm install react-router-dom

2. 设置使用模式

BrowserRouter或HashRouter

  • Router中包含了对路径改变的监听,并且会将相应的路径传递给子组件
  • BrowserRouter      =>      使用history模式
  • HashRouter           =>      使用hash模式
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import { HashRouter } from 'react-router-dom';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  
    
      
    
  
);

3. 路由映射配置

Routes

包裹所有的Route,在其中匹配一个路由


  home
} /> about
} />

Router5.x使用的是Switch组件


  
  
  {/* 重定向 */}
  

Route

Route用于路径的匹配 

  • path属性:用于设置匹配到的路径;
  • element属性:设置匹配到路径后,渲染的组件
    • Router5.x使用的是component属性
  • exact:精准匹配,只有精准匹配到完全一致的路径,才会渲染对应的组件
    • Router6.x不再支持该属性

React 之 Router - 路由详解_第1张图片

二、路由组件跳转

1. Link

 to属性:Link中最重要的属性,用于设置跳转到的路径

React 之 Router - 路由详解_第2张图片

import React, { PureComponent } from 'react';

import { Route, Routes, Link } from 'react-router-dom';
import Home from './pages/Home.jsx';
import About from './pages/About.jsx';

export class App extends PureComponent {
  render() {
    return (
      
{/* 设置组件跳转 */} 首页 关于

{/* 映射关系 : path => Component */} } /> } /> } />

footer
); } } export default App;

React 之 Router - 路由详解_第3张图片

2. NavLink

NavLink是在Link基础之上增加了一些样式属性

认匹配成功时,NavLink就会添加上一个动态的active class

React 之 Router - 路由详解_第4张图片

import React, { PureComponent } from 'react';

import { Route, Routes, NavLink } from 'react-router-dom';
import Home from './pages/Home.jsx';
import About from './pages/About.jsx';

export class App extends PureComponent {
  render() {
    return (
      
{/* 设置组件跳转 */} 首页 关于

{/* 映射关系 : path => Component */} } /> } /> } />

footer
); } } export default App;

三、Navigate导航

Navigate用于路由的重定向,当这个组件出现时,就会执行跳转到对应的to路径中

Router5.x使用的 Redirect

用法一 

import React, { PureComponent } from 'react';
import { Navigate } from 'react-router-dom';

export class Mine extends PureComponent {
  constructor(props) {
    super(props);

    this.state = {
      isLogin: false
    };
  }
  login() {
    this.setState({
      isLogin: true
    });
  }
  render() {
    const { isLogin } = this.state;
    return (
      

Mine

{/* 一旦出现Navigate,会自动跳转到对应页面 */} {!isLogin ? : }
); } } export default Mine;

用法二

用于显示默认显示的页面


  
  {/* } /> */}
  } />

  } />
  } />
  } />

四、Not Found页面配置

当随意输入一个地址,该地址无法匹配,则显示一个Not Found的页面


  } />
  } />
  } />
  } />
  {/* 当前面的路由未匹配到时, 显示 NotFound 组件 */}
  } />

五、路由嵌套

1. 创建嵌套组件

这里创建home组件的嵌套

React 之 Router - 路由详解_第5张图片

2. 配置映射关系

在App.jsx中,统一配置,router6.x之后路由配置最好写在一起

React 之 Router - 路由详解_第6张图片

3. 跳转Link && 占位组件

在home组件中进行配置

组件用于在父路由元素中作为子路由的占位元素

import React, { PureComponent } from 'react';
import { Link, Outlet } from 'react-router-dom';

export class Home extends PureComponent {
  render() {
    return (
      

Home

{/* 跳转按钮 */} 推荐 排行 {/* 占位组件 */}
); } } export default Home;

4. 效果 

React 之 Router - 路由详解_第7张图片

 六、手动路由跳转

在Router6.x版本之后,代码类的API都迁移到了hooks的写法 => useNavigate的Hook

1. 函数式组件

hook只能在函数式组件中使用

import React from 'react';

import { Route, Routes, NavLink, Navigate, useNavigate } from 'react-router-dom';
import Home from './pages/Home.jsx';
import Recommand from './pages/components/Recommand.jsx';
import Ranking from './pages/components/Ranking.jsx';
import About from './pages/About.jsx';
import Mine from './pages/Mine.jsx';
import NotFound from './pages/NotFound.jsx';
// 1. 导入组件
import Category from './pages/Category.jsx';
import Profily from './pages/Profily.jsx';

export function App(props) {
  // hooks 只能放在顶层中使用,不能放在嵌套函数、条件判断、循环中使用,否则会报错
  const navigate = useNavigate();

  function routerJump(path) {
    // 4. 跳转
    navigate(path);
  }
  return (
    
首页 关于 我的 {/* 3. 点击跳转 */}

{/* 映射关系 : path => Component */} } /> }> } /> } /> } /> } /> } /> {/* 2. 配置映射关系 */} } /> } /> {/* 当前面的路由未匹配到时, 显示 NotFound 组件 */} } />

footer
); } export default App;

2. 类组件 

如果要在类组件中使用,则需弄一个高级组件包裹一下

路由高阶组件封装

// 让类组件可以使用路由组件的API进行跳转

import { useNavigate } from 'react-router-dom';

export default function withRouter(WrapperComponent) {
  return (props) => {
    const navigate = useNavigate();

    return ;
  };
}

类组件使用

import React, { PureComponent } from 'react';

import { Route, Routes, NavLink, Navigate } from 'react-router-dom';
import About from './pages/About.jsx';
import NotFound from './pages/NotFound.jsx';
// 1. 导入组件
import Category from './pages/Category.jsx';
import Profily from './pages/Profily.jsx';

// 2. 导入高阶组件
import withRouter from './hoc/withRouter.js';

export class App extends PureComponent {
  routerJump(path) {
    // 5. 拿到增强到的router,设置跳转
    const { router } = this.props;
    router.navigate(path);
  }
  render() {
    return (
      
关于 {/* 4. 点击跳转 */}

{/* 映射关系 : path => Component */} } /> } /> {/* 2. 配置映射关系 */} } /> } /> {/* 当前面的路由未匹配到时, 显示 NotFound 组件 */} } />

footer
); } } // 3. 使用高阶组件 export default withRouter(App);

七、路由参数传递

1. 动态路由的方式

效果

React 之 Router - 路由详解_第8张图片

配置

} />

组件内跳转触发 

import React, { PureComponent } from 'react';
import withRouter from '../hoc/withRouter';

export class Category extends PureComponent {
  constructor(props) {
    super(props);
    this.state = {
      arrList: [22222, 33333, 44444, 55555]
    };
  }
  itemClick(id) {
    const { router } = this.props;
    // 跳转到详情页
    router.navigate(`/detail/${id}`);
  }
  render() {
    const { arrList } = this.state;
    return (
      <>
        
Category
    {arrList.map((item, index) => { return (
  • this.itemClick(item)} key={index}> {item}
  • ); })}
); } } export default withRouter(Category);

路由高阶组件进一步封装

// 让类组件可以使用路由组件的API

import { useNavigate, useParams } from 'react-router-dom';

export default function withRouter(WrapperComponent) {
  return (props) => {
    // 1. 跳转对象
    const navigate = useNavigate();
    // 2. 动态路由的参数 /detail/:id
    const params = useParams();

    return ;
  };
}

显示的组件

import React, { PureComponent } from 'react';

import withRouter from '../hoc/withRouter';
export class Detail extends PureComponent {
  render() {
    // 1. 通过 withRouter 高阶组件,可以获取到路由信息
    const { router } = this.props;
    return (
      <>
        
Detail
{/* 2. 通过 router.params 获取到路由参数 */}

id: {router.params.id}

); } } export default withRouter(Detail);

2. search传递参数

效果

React 之 Router - 路由详解_第9张图片

配置

import React, { PureComponent } from 'react';

import { Route, Routes, NavLink, Navigate } from 'react-router-dom';

// 2. 导入高阶组件
import withRouter from './hoc/withRouter.js';
import Detail from './pages/Detail.jsx';
import Category from './pages/Category.jsx';

export class App extends PureComponent {
  routerJump(path) {
    const { router } = this.props;
    router.navigate(path);
  }
  render() {
    return (
      
分类 {/* 5. 携带参数,使用query传参 */} 详情

{/* 4. 映射关系 : path => Component */} } /> } /> } />

footer
); } } // 3. 使用高阶组件 export default withRouter(App);

路由高阶组件再进一步封装

// 让类组件可以使用路由组件的API

import { useNavigate, useParams, useLocation, useSearchParams } from 'react-router-dom';

export default function withRouter(WrapperComponent) {
  return (props) => {
    // 1. 跳转对象
    const navigate = useNavigate();
    // 2. 动态路由的参数 /detail/:id
    const params = useParams();

    // 3. 查询字符串的参数 /detail?id=1&name=jack
    // 3.1.1 通过useLocation获取查询字符串
    // const lacationSearchs = useLocation().search;
    // console.log('searchParams', lacationSearchs); // ?name=coder&age=18 => 不太好用
    // 3.1.2 通过URLSearchParams获取查询字符串
    // const lacationSearchParams = new URLSearchParams(lacationSearchs);
    // console.log('searchParams', lacationSearchParams.get('name')); // coder

    // 3.2.1 通过useSearchParams获取查询字符串
    const [searchParams, setSearchParams] = useSearchParams();
    // console.log('searchParams', searchParams.get('name')); // coder
    const query = Object.fromEntries(searchParams.entries()); // 可直接转换为对象,Object.fromEntries(searchParams)
    // console.log('searchParams', query); // {name: "coder", age: "18"}

    return ;
  };
}

显示的组件

import React, { PureComponent } from 'react';

import withRouter from '../hoc/withRouter';
export class Detail extends PureComponent {
  render() {
    // 1. 通过 withRouter 高阶组件,可以获取到路由信息
    const { router } = this.props;
    const { name, age } = router.query;
    return (
      <>
        
Detail
{/* 2. 通过 router.params 获取到路由参数 */}

name: {name}

age: {age}

); } } export default withRouter(Detail);

八、路由配置文件

目前所有的路由定义都是直接使用Route组件,并且添加属性来完成的

但是这样的方式会让路由变得非常混乱,我们希望将所有的路由配置放到一个地方进行集中管理

  • 在早期的时候,Router并且没有提供相关的API,我们需要借助于react-router-config完成
  • 在Router6.x中,为我们提供了useRoutes API可以完成相关的配置;

1. 创建router文件夹

index.js

const routes = [];

export default routes;

2. 在App.jsx中使用

import React from 'react';

import { NavLink, useNavigate, useRoutes } from 'react-router-dom';
// 1. 导入路由相关的组件
import routes from './router';

export function App(props) {
  const navigate = useNavigate();
  function routerJump(path) {
    navigate(path);
  }
  return (
    
首页 关于 我的

{/* } /> }> } /> } /> } /> } /> } /> } /> } /> } /> */} {/* 2. 使用路由组件,渲染路由,并且传入路由配置 */} {useRoutes(routes)}

footer
); } export default App;

3. 对比

React 之 Router - 路由详解_第10张图片

4. 路由懒加载

1. index.js中配置

import React, { Suspense } from 'react';
import ReactDOM from 'react-dom/client';
import App from './App.jsx';
import { HashRouter } from 'react-router-dom';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  
    {/* 
      Suspense组件用于在组件渲染时显示一个fallback组件,直到该组件加载完成为止 
      fallback属性用于指定fallback组件,可以是任何react元素,可以是一个加载动画,也可以是一个加载提示文字
      当异步组件加载完成后,fallback组件会被卸载,然后渲染异步组件
    */}
    
      Loading...
}> );

2. router中配置

// Desc: 路由配置文件

// 同步路由配置,没进行分包处理
// import Home from '../pages/Home.jsx';
import Recommand from '../pages/components/Recommand.jsx';
import Ranking from '../pages/components/Ranking.jsx';
import About from '../pages/About.jsx';
import Mine from '../pages/Mine.jsx';
import NotFound from '../pages/NotFound.jsx';

import Category from '../pages/Category.jsx';
import Profily from '../pages/Profily.jsx';
import { Navigate } from 'react-router-dom';

// 异步路由配置,进行了分包处理 => 一般用于比较大的页面,比如登录页、注册页、首页等
import { lazy } from 'react';
// import => 会将整个文件加载进来,然后再从中导出需要的部分, 会导致整个文件被加载进来,会增加首屏加载时间 => 是webpack的语法

你可能感兴趣的:(React,react.js,javascript,前端,readt-router)