React Router(react-router-dom V6 整理)


官方文档

一个神奇的链接: React Router 官方文档

安装

运行以下命令安装React Router:

npm install react-router-dom@6 --save

注意:react-router-dom 包含所有内容,导入组件时应该从react-router-dom中导入,而不应该从 react-router中导入,否则,会意外地在应用中导入不匹配的库版本;

基本用法

在Web应用程序中开启 React Router 功能

// index.js

import React from 'react';
import { createRoot } from 'react-dom/client';
import { BrowserRouter } from 'react-router-dom';
import App from './App';

const container = document.getElementById('root');
const root = createRoot(container);
root.render(
  // 通过在应用入口添加 BrowserRouter 组件开启 React Router 功能
  
    
      
    
  
);

注意:web 应用程序中一般使用 BrowserRouter 组件, 还用另一种 HashRouter 组件方式;
这两种方式的区别:

  1. 底层原理不一样:
    BrowserRouter调用的是 H5 history API,低版本兼容性问题;
    HashRouter 使用的是 URL 哈希值;
  2. 地址栏表现形式不一样:
    BrowserRouter的路径:localhost:3000/index
    HashRouter的路径:localhost:3000/#/index
  3. 刷新后对路由 state 参数的影响
    BrowserRouter没有任何影响,因为 state 保存在 history 对象中
    HashRouter刷新后会导致路由 state 参数的丢失

值得注意的是,官方强烈建议不要使用 HashRouter;

配置路由

点击查看代码
// App.js

// 导入 Route, Routes 组件
import { Route, Routes } from 'react-router-dom';

function App() {
  return (
    
	  {/* 页面默认导航到 Home 组件(页面上显示 Home Compontent) */}
      } />
	  {/* 在地址输入 http://localhost:3000/about 导航到 About 组件(页面上显示 About Compontent) */}
      } />
    
  );
}

const Home = (props) => {
  return 
Home Compontent
; } const About = (props) => { return
About Compontent
; } export default App;

在以前版本的 React Router 中,必须以某种方式对路由进行排序,以便在多个路由与不明确的 URL 匹配时获得要呈现的正确路由。V6更智能,会选择最具体的匹配;

添加 "不匹配" 路由

点击查看代码
// App.js

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

function App() {
  return (
    
      } />
      } />
      {/* 当没有其他路由与 URL 匹配时,匹配 path='*'的路由 */}
      } />
    
  );
}

const Home = (props) => {
  return 
Home Compontent
; } const About = (props) => { return
About Compontent
; } const NotFount = (props) => { return
NotFount !!!
; } export default App;

当没有其他路由与 URL 匹配时,才会匹配 path='*'路由。此路由将匹配任何 URL,但优先级最弱,因此路由器仅在没有其他路由匹配时才会选择它;

使用链接导航

点击查看代码
// App.js

// 导入 Link 组件
import { Route, Routes, Link } from 'react-router-dom';

function App() {
  return (
    
	  {/* 页面默认导航到 Home 组件(渲染 Home 组件, 页面显示 About Compontent 链接) */}
      } />
      } />
    
  );
}

const Home = (props) => {
  return 
{/* 点击 About Link 链接跳转至 http://localhost:3000/about 画面显示 About 组件内容(Home Link链接) */} About Link
; } const About = (props) => { return
{/* 点击 Home Link 链接跳转至 http://localhost:3000/ 画面显示 Home 组件内容(About Link链接) */} Home Link
; } export default App;

使用嵌套路由

点击查看代码
// App.js

// 导入 Link, Outlet 组件
import { Route, Routes, Link, Outlet } from 'react-router-dom';

function App() {
  return (
    
      } >
        } />
        } />
        {/* 默认子路由
            如果导航栏地址为 http://localhost:3000,此时子路由渲染位置(Outlet)为空白,
            增加以下配置,子路由渲染位置(Outlet)渲染 
         */}
        } />
      
    
  );
}

const Home = (props) => {
  return <>
    
About Link | {" "} Setting Link
{/* Outlet 为嵌套子路由的出口,比如:点击 About Link 链接, 浏览器地址变为 http://localhost:3000/about 在此渲染路由地址为 /about 的组件(在此显示: About Compontent) */}
; } const About = (props) => { return
About Compontent
; } const Setting = (props) => { return
Setting Compontent
; } const List = (props) => { return
List Compontent
; } export default App;

这是 React Router 最强大的功能之一,在实际开发中,大多数 UI 都是一系列嵌套布局,React Router 通过这种嵌套路由的方式实现了一些自动、持久的布局处理;

使用活动链接

点击查看代码
// App.js

// 导入 NavLink 组件
import { Route, Routes, NavLink, Outlet } from 'react-router-dom';

function App() {
  return (
    
      } >
        } />
        } />
        } />
      
    
  );
}

const Home = (props) => {
  return <>
    
{/* 接收一个style 或者 className 属性 属性值为一个回调函数,可以通过 isActive 的值判断 链接是否处于活动状态,从而实现给活动链接节点添加样式的效果 示例效果:点击哪个链接,目标链接字体变红 */} navColor(isActive)} to='/about' > About Link | {" "} navColor(isActive)} to='/setting' > Setting Link
; } const About = (props) => { return
About Compontent
; } const Setting = (props) => { return
Setting Compontent
; } const List = (props) => { return
List Compontent
; } const navColor = (isActive) => { return {color: isActive ? 'red' : ""} } export default App;

主要实现了给当前激活的链接设置一个式样,支持 styleclassName 这两种属性;

读取 URL 参数

点击查看代码
// 导入 useParams 组件
import { Route, Routes, NavLink, Outlet, useParams } from 'react-router-dom';

function App() {
  return (
    
      } >
        } >
          } />
        
      
    
  );
}

const Home = (props) => {
  return <>
    
navColor(isActive)} to='/list' > List Link
; } const Item = (props) => { // 从 URL 获取参数::id const params = useParams(); return

Item: {params.id}

; } const List = (props) => { const list = [ { name: "赵云", no: 100 }, { name: "马超", no: 101 } ] return
{list.map((item) => { return ( navColor(isActive)} to={`/list/${item.no}`} key={item.no} > {item.name} ) })}
{/* 指定子路由 /list/? 的渲染位置 */}
; } const navColor = (isActive) => { return { color: isActive ? 'red' : "", marginRight: '10px' } } export default App;

与 V5 的区别

  1. 替代
    写法上的比较:
    // v5 写法
    // 引入 react-router
    import { Route, Switch } from 'react-router-dom';
    function App() {
      return (
    	  
    		{/* 路由配置 */}
    	  
      );
    }
    
    // v6 写法
    import { Route, Routes } from 'react-router-dom';
    function App() {
      return (
    	  // Routes 替换 Switch
    	 
    	  {/* 路由配置 */}
    	
      );
    }
    
    v6 的优点:
    v6 提供了功能更强大的 Routes 组件来代替 Switch 组件,Routes 不再按顺序匹配路径,而是采用了一种自动匹配最佳路径的方法;
  2. 不再支持子组件,改为使用 element 属性;并且不再需要 exact 属性了
    写法上的比较:
    // v5 写法
    // 引入 react-router
    import { Route, Switch } from 'react-router-dom';
    function App() {
      return (
    	  
    		
    		  
    		
    	  
      );
    }
    
    // v6 写法
    import { Route, Routes } from 'react-router-dom';
    function App() {
      return (
    	
    	   } />
    	
      );
    }
    
    v6 的优点:
    1. v6 提供的 element 属性, 可以使开发者更加方便的注入想要的 props;
    2. v6 中的 path 属性是相对的;
    3. 可以按照所需的任何顺序放置路由,路由器将自动检测当前URL的最佳路由;
  3. 移除了 activeClassName 属性
    v6写法:
    import { NavLink } from 'react-router-dom';
    function App() {
      return (
    	<>
    	  {/* className 写法 */}
    	   {
    		  return isActive ? "highlight" : "";
    		}} 
    		to="home">Home
    	  {/* style 写法 */}
    	   {
    		  return {
    			color: isActive ? "red" : ""
    		  }
    		}}
    	  >About
    	
      );
    }
    
  4. 移除 ,改为使用
    写法上的对比:
    // v6 写法
    import { Navigate, Route, Routes } from 'react-router-dom';
    function App() {
      return (
    	
    	  } /> 
    	
      );
    }
    
  5. 支持相对位置
    // 配置路由
    
    	    
    	        
    	    
    
    
    // 当前 URL 是 /app/home
                   => 
                => 
             => 
          => 
    
  6. 新增
    关于 ,参考本文的嵌套路由节点; 此组件是一个占位符,告诉 React Router 嵌套的内容应该放到哪里; 通过 可以将所有的路由(嵌套的子路由)配置合并在一起,可进行路由的统一管理,增加了代码可维护性;
  7. 使用 useNavigate 实现编程式导航,从而代替 useHistory
    // v6 写法
    import { useNavigate } from 'react-router-dom';
    function App() {
      const navigate = useNavigate();
    
      const handleClick = () => {
    	navigate('/home');  // push
    	// 重定向
    	// navigate('/home', {replace: true});
      };
    
      return (
    	
    ); }
    主要写法变更:
    • history.push("/") => navigate("/")
    • history.replace("/") => navigate("/",{ replace: true })
    • history.goBack() => navigate(-1)
    • history.goForward() => navigate(1)
    • history.go(2) => navigate(2)
  8. 一系列的 Hooks
    hooks名 作用 说明
    useParams 返回当前参数 根据路径读取参数
    useNavigate 返回当前路由 代替原有V5中的 useHistory
    useOutlet 返回根据路由生成的element
    useLocation 返回当前的location 对象
    useRoutes 同Routers组件一样,只不过是在js中使用
    useSearchParams 用来匹配URL中?后面的搜索参数

总结

本文主要记录了一下 React Router V6 的一些基本用法以及对V5的比较,有了这些知识的支撑,足以应付大多数日常开发了;v6 版本基于全新的路由算法带来强大的功能和 hooks,并且重新实现了 useNavigate 来替代 useHistory ,整体上更加好理解;
先记录这么多,后续持续更新!!!