得顺天意 發表於 2022-4-11 09:54:00

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

<h2 id="官方文档">官方文档</h2>
<blockquote>
<p><span style="color: rgba(255, 0, 0, 1)"><strong>一个神奇的链接</strong>:</span> React Router 官方文档</p>
</blockquote>
<h2 id="安装">安装</h2>
<p>运行以下命令安装React Router:</p>
<pre><code>npm install react-router-dom@6 --save
</code></pre>
<p><span style="color: rgba(220, 20, 60, 1)"><strong>注意:</strong></span><code>react-router-dom</code> 包含所有内容,导入组件时应该从<code>react-router-dom</code>中导入,而不应该从 <code>react-router</code>中导入,否则,会意外地在应用中导入不匹配的库版本;</p>
<h2 id="基本用法">基本用法</h2>
<h3 id="在web应用程序中开启-react-router-功能">在Web应用程序中开启 React Router 功能</h3>
<pre><code class="language-jsx">// 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 功能
&lt;BrowserRouter&gt;
    &lt;React.StrictMode&gt;
      &lt;App /&gt;
    &lt;/React.StrictMode&gt;
&lt;/BrowserRouter&gt;
);
</code></pre>
<p><span style="color: rgba(220, 20, 60, 1)"><strong>注意:</strong></span>web 应用程序中一般使用<code>BrowserRouter</code> 组件, 还用另一种 <code>HashRouter</code> 组件方式;<br>
这两种方式的区别:</p>
<ol>
<li>底层原理不一样:<br>
<code>BrowserRouter</code>调用的是 <strong>H5 history API</strong>,低版本兼容性问题;<br>
<code>HashRouter</code> 使用的是 <strong>URL</strong> 哈希值;</li>
<li>地址栏表现形式不一样:<br>
<code>BrowserRouter</code>的路径:localhost:3000/index<br>
<code>HashRouter</code>的路径:localhost:3000/#/index</li>
<li>刷新后对路由 <strong>state</strong> 参数的影响<br>
<code>BrowserRouter</code>没有任何影响,因为 <strong>state</strong> 保存在 <strong>history</strong> 对象中<br>
<code>HashRouter</code>刷新后会导致路由 <strong>state</strong> 参数的丢失</li>
</ol>
<p>值得注意的是,官方强烈建议不要使用 <code>HashRouter</code>;</p>
<h3 id="配置路由">配置路由</h3>
<details>
<summary>点击查看代码</summary>
<pre><code class="language-jsx">// App.js

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

function App() {
return (
    &lt;Routes&gt;
          {/* 页面默认导航到 Home 组件(页面上显示 Home Compontent) */}
      &lt;Route path='/' element={&lt;Home /&gt;} /&gt;
          {/* 在地址输入 http://localhost:3000/about 导航到 About 组件(页面上显示 About Compontent) */}
      &lt;Route path='/about' element={&lt;About /&gt;} /&gt;
    &lt;/Routes&gt;
);
}

const Home = (props) =&gt; {
return &lt;div&gt;Home Compontent&lt;/div&gt;;
}

const About = (props) =&gt; {
return &lt;div&gt;About Compontent&lt;/div&gt;;
}

export default App;
</code></pre>
</details>
<p>在以前版本的 <strong>React Router</strong> 中,必须以某种方式对路由进行排序,以便在多个路由与不明确的 <strong>URL</strong> 匹配时获得要呈现的正确路由。V6更智能,会选择最具体的匹配;</p>
<h3 id="添加-不匹配-路由">添加 "不匹配" 路由</h3>
<details>
<summary>点击查看代码</summary>
<pre><code class="language-jsx">// App.js

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

function App() {
return (
    &lt;Routes&gt;
      &lt;Route path='/' element={&lt;Home /&gt;} /&gt;
      &lt;Route path='/about' element={&lt;About /&gt;} /&gt;
      {/* 当没有其他路由与 URL 匹配时,匹配 path='*'的路由 */}
      &lt;Route path='*' element={&lt;NotFount /&gt;} /&gt;
    &lt;/Routes&gt;
);
}

const Home = (props) =&gt; {
return &lt;div&gt;Home Compontent&lt;/div&gt;;
}

const About = (props) =&gt; {
return &lt;div&gt;About Compontent&lt;/div&gt;;
}

const NotFount = (props) =&gt; {
return &lt;div&gt;NotFount !!!&lt;/div&gt;;
}

export default App;
</code></pre>
</details>
<p>当没有其他路由与 URL 匹配时,才会匹配 <code>path='*'</code>路由。此路由将匹配任何 URL,但优先级最弱,因此路由器仅在没有其他路由匹配时才会选择它;</p>
<h3 id="使用链接导航">使用链接导航</h3>
<details>
<summary>点击查看代码</summary>
<pre><code class="language-jsx">// App.js

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

function App() {
return (
    &lt;Routes&gt;
          {/* 页面默认导航到 Home 组件(渲染 Home 组件, 页面显示 About Compontent 链接) */}
      &lt;Route path='/' element={&lt;Home /&gt;} /&gt;
      &lt;Route path='/about' element={&lt;About /&gt;} /&gt;
    &lt;/Routes&gt;
);
}

const Home = (props) =&gt; {
return &lt;div&gt;
    {/* 点击 About Link 链接跳转至 http://localhost:3000/about
      画面显示 About 组件内容(Home Link链接)
      */}
    &lt;Link to='/about'&gt;About Link&lt;/Link&gt;
&lt;/div&gt;;
}

const About = (props) =&gt; {
return &lt;div&gt;
    {/* 点击 Home Link 链接跳转至 http://localhost:3000/
      画面显示 Home 组件内容(About Link链接)
      */}
    &lt;Link to='/'&gt;Home Link&lt;/Link&gt;
&lt;/div&gt;;
}

export default App;
</code></pre>
</details>
<h3 id="使用嵌套路由">使用嵌套路由</h3>
<details>
<summary>点击查看代码</summary>
<pre><code class="language-jsx">// App.js

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

function App() {
return (
    &lt;Routes&gt;
      &lt;Route path='/' element={&lt;Home /&gt;} &gt;
      &lt;Route path='about' element={&lt;About /&gt;} /&gt;
      &lt;Route path='setting' element={&lt;Setting /&gt;} /&gt;
      {/* 默认子路由
            如果导航栏地址为 http://localhost:3000,此时子路由渲染位置(Outlet)为空白,
            增加以下配置,子路由渲染位置(Outlet)渲染 &lt;List /&gt;
         */}
      &lt;Route index element={&lt;List /&gt;} /&gt;
      &lt;/Route&gt;
    &lt;/Routes&gt;
);
}

const Home = (props) =&gt; {
return &lt;&gt;
    &lt;div&gt;
      &lt;Link to='/about'&gt;About Link&lt;/Link&gt; | {" "}
      &lt;Link to='/setting'&gt;Setting Link&lt;/Link&gt;
    &lt;/div&gt;
    &lt;div style={{padding: '20px', margin: '10px', borderTop: '1px solid'}}&gt;
      {/* Outlet 为嵌套子路由的出口,比如:点击 About Link 链接,
          浏览器地址变为 http://localhost:3000/about
          在此渲染路由地址为 /about 的组件(在此显示: About Compontent)
       */}
      &lt;Outlet /&gt;
    &lt;/div&gt;
&lt;/&gt;;
}

const About = (props) =&gt; {
return &lt;div&gt;
    About Compontent
&lt;/div&gt;;
}

const Setting = (props) =&gt; {
return &lt;div&gt;
    Setting Compontent
&lt;/div&gt;;
}

const List = (props) =&gt; {
return &lt;div&gt;
    List Compontent
&lt;/div&gt;;
}

export default App;
</code></pre>
</details>
<p>这是 <strong>React Router</strong> 最强大的功能之一,在实际开发中,大多数 UI 都是一系列嵌套布局,<strong>React Router</strong> 通过这种嵌套路由的方式实现了一些自动、持久的布局处理;</p>
<h3 id="使用活动链接">使用活动链接</h3>
<details>
<summary>点击查看代码</summary>
<pre><code class="language-jsx">// App.js

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

function App() {
return (
    &lt;Routes&gt;
      &lt;Route path='/' element={&lt;Home /&gt;} &gt;
      &lt;Route path='about' element={&lt;About /&gt;} /&gt;
      &lt;Route path='setting' element={&lt;Setting /&gt;} /&gt;
      &lt;Route index element={&lt;List /&gt;} /&gt;
      &lt;/Route&gt;
    &lt;/Routes&gt;
);
}

const Home = (props) =&gt; {
return &lt;&gt;
    &lt;div&gt;
      {/* &lt;NavLink /&gt; 接收一个style 或者 className 属性
          属性值为一个回调函数,可以通过 isActive 的值判断
          链接是否处于活动状态,从而实现给活动链接节点添加样式的效果
          示例效果:点击哪个链接,目标链接字体变红
       */}
      &lt;NavLink
      style={({ isActive }) =&gt; navColor(isActive)}
      to='/about'
      &gt;
      About Link
      &lt;/NavLink&gt; | {" "}
      &lt;NavLink
      style={({isActive}) =&gt; navColor(isActive)}
      to='/setting'
      &gt;
      Setting Link
      &lt;/NavLink&gt;
    &lt;/div&gt;
    &lt;div style={{ padding: '20px', margin: '10px', borderTop: '1px solid' }}&gt;
      &lt;Outlet /&gt;
    &lt;/div&gt;
&lt;/&gt;;
}

const About = (props) =&gt; {
return &lt;div&gt;
    About Compontent
&lt;/div&gt;;
}

const Setting = (props) =&gt; {
return &lt;div&gt;
    Setting Compontent
&lt;/div&gt;;
}

const List = (props) =&gt; {
return &lt;div&gt;
    List Compontent
&lt;/div&gt;;
}

const navColor = (isActive) =&gt; {
return {color: isActive ? 'red' : ""}
}

export default App;
</code></pre>
</details>
<p>主要实现了给当前激活的链接设置一个式样,支持 <strong>style</strong> 和 <strong>className</strong> 这两种属性;</p>
<h3 id="读取-url-参数">读取 URL 参数</h3>
<details>
<summary>点击查看代码</summary>
<pre><code class="language-jsx">// 导入 useParams 组件
import { Route, Routes, NavLink, Outlet, useParams } from 'react-router-dom';

function App() {
return (
    &lt;Routes&gt;
      &lt;Route path='/' element={&lt;Home /&gt;} &gt;
      &lt;Route path='list' element={&lt;List /&gt;} &gt;
          &lt;Route path=':id' element={&lt;Item /&gt;} /&gt;
      &lt;/Route&gt;
      &lt;/Route&gt;
    &lt;/Routes&gt;
);
}

const Home = (props) =&gt; {
return &lt;&gt;
    &lt;div&gt;
      &lt;NavLink
      style={({ isActive }) =&gt; navColor(isActive)}
      to='/list'
      &gt;
      List Link
      &lt;/NavLink&gt;
    &lt;/div&gt;
    &lt;div style={{ padding: '20px', margin: '10px', borderTop: '1px solid' }}&gt;
      &lt;Outlet /&gt;
    &lt;/div&gt;
&lt;/&gt;;
}

const Item = (props) =&gt; {
// 从 URL 获取参数::id
const params = useParams();
return &lt;h2&gt;Item: {params.id}&lt;/h2&gt;;
}

const List = (props) =&gt; {
const list = [
    {
      name: "赵云",
      no: 100
    },
    {
      name: "马超",
      no: 101
    }
]
return &lt;div&gt;
    {list.map((item) =&gt; {
      return (&lt;NavLink
      style={({isActive}) =&gt; navColor(isActive)}
      to={`/list/${item.no}`}
      key={item.no}
      &gt;
      {item.name}
      &lt;/NavLink&gt;)
    })}
    &lt;div className='content'&gt;
      {/* 指定子路由 /list/? 的渲染位置 */}
      &lt;Outlet /&gt;
    &lt;/div&gt;
&lt;/div&gt;;
}

const navColor = (isActive) =&gt; {
return {
    color: isActive ? 'red' : "",
    marginRight: '10px'
}
}

export default App;
</code></pre>
</details>
<h2 id="与-v5-的区别">与 V5 的区别</h2>
<ol>
<li><code>&lt;Routes&gt;</code> 替代 <code>&lt;Switch&gt;</code><br>
<strong>写法上的比较:</strong><pre><code class="language-jsx">// v5 写法
// 引入 react-router
import { Route, Switch } from 'react-router-dom';
function App() {
return (
          &lt;Switch&gt;
                {/* 路由配置 */}
          &lt;/Switch&gt;
);
}

// v6 写法
import { Route, Routes } from 'react-router-dom';
function App() {
return (
          // Routes 替换 Switch
        &lt;Routes&gt;
          {/* 路由配置 */}
        &lt;/Routes&gt;
);
}
</code></pre>
<strong>v6 的优点:</strong><br>
v6 提供了功能更强大的 <strong>Routes</strong> 组件来代替 <strong>Switch</strong> 组件,<strong>Routes</strong> 不再按顺序匹配路径,而是采用了一种自动匹配最佳路径的方法;</li>
<li><code>&lt;Route&gt;</code> 不再支持子组件,改为使用 <strong>element</strong> 属性;并且不再需要 <strong>exact</strong> 属性了<br>
<strong>写法上的比较:</strong><pre><code class="language-jsx">// v5 写法
// 引入 react-router
import { Route, Switch } from 'react-router-dom';
function App() {
return (
          &lt;Switch&gt;
                &lt;Route exact path='/home'&gt;
                  &lt;Home /&gt;
                &lt;/Route&gt;
          &lt;/Switch&gt;
);
}

// v6 写法
import { Route, Routes } from 'react-router-dom';
function App() {
return (
        &lt;Routes&gt;
          &lt;Route path='/home' element={&lt;Home /&gt; } /&gt;
        &lt;/Routes&gt;
);
}
</code></pre>
<strong>v6 的优点:</strong>
<ol>
<li>v6 提供的 <strong>element</strong> 属性, 可以使开发者更加方便的注入想要的 <strong>props</strong>;</li>
<li>v6 <route> 中的 <strong>path</strong> 属性是相对的;</route></li>
<li>可以按照所需的任何顺序放置路由,路由器将自动检测当前URL的最佳路由;</li>
</ol>
</li>
<li>移除了 <code>&lt;NavLink&gt;</code> 的 <strong>activeClassName</strong> 属性<br>
<strong>v6写法:</strong><pre><code class="language-jsx">import { NavLink } from 'react-router-dom';
function App() {
return (
        &lt;&gt;
          {/* className 写法 */}
          &lt;NavLink
                className={({isActive}) =&gt; {
                  return isActive ? "highlight" : "";
                }}
                to="home"&gt;Home&lt;/NavLink&gt;
          {/* style 写法 */}
          &lt;NavLink
                to="about"
                style={({isActive}) =&gt; {
                  return {
                        color: isActive ? "red" : ""
                  }
                }}
          &gt;About&lt;/NavLink&gt;
        &lt;/&gt;
);
}
</code></pre>
</li>
<li>移除 <code>&lt;Redirect&gt;</code>,改为使用 <code>&lt;Navigate&gt;</code><br>
<strong>写法上的对比:</strong><pre><code class="language-jsx">// v6 写法
import { Navigate, Route, Routes } from 'react-router-dom';
function App() {
return (
        &lt;Routes&gt;
          &lt;Route path='/' element={&lt;Navigate replace to="/home" /&gt;} /&gt;
        &lt;/Routes&gt;
);
}
</code></pre>
</li>
<li><code>&lt;Link to&gt;</code>支持相对位置<pre><code class="language-jsx">// 配置路由
&lt;Route path="app"&gt;
          &lt;Route path="home"&gt;
                &lt;Route path="list" /&gt;
          &lt;/Route&gt;
&lt;/Route&gt;

// 当前 URL 是 /app/home
&lt;Link to="list"&gt;               =&gt; &lt;a href="/app/home/list"&gt;
&lt;Link to="../list"&gt;            =&gt; &lt;a href="/app/list"&gt;
&lt;Link to="../../list"&gt;         =&gt; &lt;a href="/list"&gt;
&lt;Link to="../../../list"&gt;      =&gt; &lt;a href="/list"&gt;
</code></pre>
</li>
<li>新增 <code>&lt;Outlet&gt;</code><br>
关于 <code>&lt;Outlet&gt;</code>,参考本文的<strong>嵌套路由</strong>节点; 此组件是一个占位符,告诉 React Router 嵌套的内容应该放到哪里; 通过 <code>&lt;Outlet&gt;</code> 可以将所有的路由(嵌套的子路由)配置合并在一起,可进行路由的统一管理,增加了代码可维护性;</li>
<li>使用 <strong>useNavigate</strong> 实现编程式导航,从而代替 <strong>useHistory</strong><pre><code class="language-jsx">// v6 写法
import { useNavigate } from 'react-router-dom';
function App() {
const navigate = useNavigate();

const handleClick = () =&gt; {
        navigate('/home');// push
        // 重定向
        // navigate('/home', {replace: true});
};

return (
        &lt;div&gt;
          &lt;button onClick={handleClick}&gt;返回首页&lt;/button&gt;
        &lt;/div&gt;
);
}
</code></pre>
主要写法变更:
<ul>
<li><code>history.push("/") =&gt; navigate("/")</code></li>
<li><code>history.replace("/") =&gt; navigate("/",{ replace: true })</code></li>
<li><code>history.goBack() =&gt; navigate(-1)</code></li>
<li><code>history.goForward() =&gt; navigate(1)</code></li>
<li><code>history.go(2) =&gt; navigate(2)</code></li>
</ul>
</li>
<li>一系列的 <strong>Hooks</strong>
<table>
<thead>
<tr>
<th style="text-align: left">hooks名</th>
<th style="text-align: left">作用</th>
<th style="text-align: left">说明</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: left"><code>useParams</code></td>
<td style="text-align: left">返回当前参数</td>
<td style="text-align: left">根据路径读取参数</td>
</tr>
<tr>
<td style="text-align: left"><code>useNavigate</code></td>
<td style="text-align: left">返回当前路由</td>
<td style="text-align: left">代替原有V5中的 useHistory</td>
</tr>
<tr>
<td style="text-align: left"><code>useOutlet</code></td>
<td style="text-align: left">返回根据路由生成的element</td>
<td style="text-align: left"></td>
</tr>
<tr>
<td style="text-align: left"><code>useLocation</code></td>
<td style="text-align: left">返回当前的location 对象</td>
<td style="text-align: left"></td>
</tr>
<tr>
<td style="text-align: left"><code>useRoutes</code></td>
<td style="text-align: left">同Routers组件一样,只不过是在js中使用</td>
<td style="text-align: left"></td>
</tr>
<tr>
<td style="text-align: left"><code>useSearchParams</code></td>
<td style="text-align: left">用来匹配URL中?后面的搜索参数</td>
<td style="text-align: left"></td>
</tr>
</tbody>
</table>
</li>
</ol>
<h2 id="总结">总结</h2>
<p>本文主要记录了一下 <strong>React Router V6</strong> 的一些基本用法以及对V5的比较,有了这些知识的支撑,足以应付大多数日常开发了;<strong>v6</strong> 版本基于全新的路由算法带来强大的功能和 <strong>hooks</strong>,并且重新实现了 <strong>useNavigate</strong> 来替代 <strong>useHistory</strong> ,整体上更加好理解;<br>
先记录这么多,后续持续更新!!!</p><br><br>
来源:https://www.cnblogs.com/operate/p/16082907.html
頁: [1]
查看完整版本: React Router(react-router-dom V6 整理)