使用 React Router 优化单页应用程序

2025-06-04

使用 React Router 优化单页应用程序

React 通常用于构建单页应用 (SPA)。SPA 通常包含多个页面视图。当从一个页面视图导航到另一个页面视图时,重新加载整个页面视图是一项繁琐且效率低下的任务。事实上,这削弱了 SPA 的优势。为了正常工作,SPA 必须在需要时渲染部分视图,而不是重新加载整个页面。

在 SPA 应用中,从一个页面导航到另一个页面时,路由是必不可少的。路由可以分为两种:静态路由和动态路由。SPA 应用采用动态路由。在本教程中,我们将讨论 React 应用中使用的一种流行路由库,即React Router

这篇文章最初发表于此处

目录

  • 要求
  • 入门
  • 使用 React Router 的第一个路由
  • 什么是 BrowserRouter?
  • 链接组件
  • 使用 NavLink 进行活动链接
  • 向路由添加参数
  • 结论

要求

  • NodeJSv8.x.x或更高版本以及 npm/yarn 一起安装
  • create-react-app在本地开发机器上全局安装,生成新的 React 项目

奖励:您还可以使用它npx来生成新的 React 项目,而无需安装create-react-app

入门

要创建新的 React 项目,请在本地计算机上的所需位置运行以下命令。

create-react-app react-router-v4-demo
Enter fullscreen mode Exit fullscreen mode

项目生成后,遍历新创建的目录。此策略是生成新 React 应用的默认方法。

React Router作为一个库包含三个不同的 npm 包。

  • 反应路由器
  • react-router-dom
  • React-router-native

每个包都有不同的用例。第一个react-router是核心包,与上面列出的后两个包一起使用。react-router-dom构建 Web 应用程序时必须使用。这也是我们将在本教程中使用的。最后一个react-router-native通常用于React Native应用程序。

要在 React 应用中添加 React Router,请从终端窗口执行以下命令。

yarn add react-router-dom
Enter fullscreen mode Exit fullscreen mode

请注意,在本教程的其余部分,我们将使用yarnJavaScript 包管理器来添加或删除依赖项。如果您想使用npm,也没人会阻止您。

要运行 React 应用,请转到终端窗口并执行命令 npm start。这将启动开发服务器。您将在 URL 上的 Web 浏览器窗口中看到默认的样板项目屏幕http://localhost:3000/

SS1

使用 React Router 的第一个路由

为了在 React 应用程序中创建第一条路由,让我们BrowserRouterreact-router库中导入。

import React from "react"
import { BrowserRouter as Router, Route } from "react-router-dom"
Enter fullscreen mode Exit fullscreen mode

要创建路由,我们使用<Route>from react-router-dom。路由逻辑就放在此处。它渲染组件的 UI。A<Route>有一个名为 的 prop path,它始终与应用程序的当前位置匹配。基于此 prop,所需的组件将被渲染。当组件未渲染时,Route返回 null。组件名称也作为 prop 传递component。请看下面的代码片段。

function App() {
    return (
        <Router>
            <Route path='/' component={Home} />
        </Router>
    )
}
Enter fullscreen mode Exit fullscreen mode

有一个函数App组件,它返回一个BrowserRouter包含第一个Route组件的 a 。 apath当前指向Home具有以下 UI 逻辑的组件。

function Home() {
    return (
        <div>
            <h1>Home Component</h1>
        </div>
    )
}
Enter fullscreen mode Exit fullscreen mode

现在,访问端口上的 URL 3000,您将看到Home正在渲染的组件。

SS2

这是一个最简单的示例。现在让我们添加另一个与 具有相同属性的路由。使用与 类似的渲染逻辑Home调用此路由AboutHome

function About() {
    return (
        <div>
            <h1>About Component</h1>
        </div>
    )
}
Enter fullscreen mode Exit fullscreen mode

现在将这个功能组件添加为第二个路由,位于Home路由下方。另外,将这两个路由添加到一个div元素内。路由器组件只能容纳一个子元素,添加一个可以div解决这个问题,并允许路由器组件拥有任意数量的子元素。

function App() {
    return (
        <Router>
            <div>
                <Route path='/' component={Home} />
                <Route path='/about' component={About} />
            </div>
        </Router>
    )
}
Enter fullscreen mode Exit fullscreen mode

尝试访问该 URL http://localhost:3000/about。您会注意到两个组件现在都在路径上渲染/about

SS3

造成这种情况的原因是,React Router 内部使用的正则表达式引擎会将以正斜杠开头的两个路由视为/相等。为了解决这个问题,我们可以在 Home 路由上使用另一个名为 的重要 prop exact

<Router>
    <div>
        <Route path='/' exact component={Home} />
        <Route path='/about' component={About} />
    </div>
</Router>
Enter fullscreen mode Exit fullscreen mode

这个 exact 也称为限定符,它规定路径必须与 完全匹配,/并且后面没有任何内容,例如/about。现在,如果您访问该 URL 的浏览器窗口,http://localhost:3000/about您会注意到这次只有 about 组件被渲染了。

SS4

什么是 BrowserRouter?

你还记得之前读到过,它只react-router-dom用于 Web 应用程序吗?其实,react-router-dom这个库包含两种类型的路由器 API,供 React 应用程序使用。一种叫做BrowserRouter,你在上一节中已经看到过它的工作原理。另一种叫做HashRouter

ABrowserRouter总是监听像 这样的 URL ,http://localhost:3000/about而 则HashRouter会有http://localhost:3000/#/about,顾名思义,它#在 和 之间使用了哈希值。那么我们为什么要使用 呢BrowserRouter

BrowserRouter在现代 Web 应用中非常流行。其主要原因是它使用 HTML5 History API 来跟踪 React 应用的路由历史记录。它HashRouter有一个在旧版浏览器中的用例,在旧版浏览器中window.location.hash仍然用于跟踪 SPA 中的路由。

DIY锻炼👇

这里有个小任务需要你完成。修改目录结构,如下图所示,并将两个功能组件Homeabout组件文件分开,以便将来它们随着更多 JSX 的出现而需要渲染。

SS5

如果你愿意,完全可以跳过这一步,直接进入下一部分。但完成这项小任务将有助于你理解上述概念。

链接组件

要在 HTML 网页之间导航,可以使用<a href=""></a>锚标记。然而,使用这种传统方法会导致浏览器刷新。为了解决这个问题,React Router API 提供了一个Link组件,可用于导航到特定的 URL 或组件。

让我们尝试利用这些新知识创建一个导航菜单。从文件react-router-dom中导入链接App.js。以下是修改后的 App 组件代码片段。

// App.js

import React from "react"
import { BrowserRouter as Router, Route, Link } from "react-router-dom"

import Home from "./components/Home"
import About from "./components/About"

function App() {
    return (
        <Router>
            <div>
                <nav style={{ margin: 10 }}>
                    <Link to='/' style={{ padding: 10 }}>
                        Home
                    </Link>

                    <Link to='/about' style={{ padding: 10 }}>
                        About
                    </Link>
                </nav>
                <Route path='/' exact component={Home} />
                <Route path='/about' component={About} />
            </div>
        </Router>
    )
}

export default App
Enter fullscreen mode Exit fullscreen mode

在上面的代码片段中,请注意所有链接都添加到所有路由组件之前。其中的样式属性style目前是可选的。启动开发服务器并访问浏览器窗口,您会注意到顶部弹出一个导航菜单。尝试点击链接在不同组件之间导航。

SS5

无论在 React 项目中的何处Link渲染,锚点<a>都会在应用程序的 HTML 中渲染。

使用 NavLink 进行活动链接

在 React Router API 中,NavLink是组件的扩展版本Link。你可以说它是一种特殊类型的组件,Link当匹配到当前路由时,它可以将自身样式设置为表示活动状态。

为了证明这一点,首先,让我们Link用文件NavLink中的所有标签替换它App.js

// App.js
import React from "react"
import { BrowserRouter as Router, Route, NavLink } from "react-router-dom"

import Home from "./components/Home"
import About from "./components/About"

function App() {
    return (
        <Router>
            <div>
                <nav style={{ margin: 10 }}>
                    <NavLink to='/' style={{ padding: 10 }}>
                        Home
                    </NavLink>

                    <NavLink to='/about' style={{ padding: 10 }}>
                        About
                    </NavLink>
                </nav>
                <Route path='/' exact component={Home} />
                <Route path='/about' component={About} />
            </div>
        </Router>
    )
}

export default App
Enter fullscreen mode Exit fullscreen mode

此时,每个NavLink链接的行为都与普通Link组件相同,这意味着目前没有任何变化。要激活链接,请activeClassName为其添加一个 prop。如下所示。

<NavLink to='/' style={{ padding: 10 }} activeClassName='active'>
Enter fullscreen mode Exit fullscreen mode

为了设置相应的 CSS 使其工作,请打开App.css文件并添加以下内容。

a {
    padding: 10px;
}

a,
a:visited {
    color: blue;
}

a.active {
    color: red;
}
Enter fullscreen mode Exit fullscreen mode

不要忘记在里面导入这个文件App.js。另外,修改about路由以使其具有activeClassName

import "./App.css"

// ...

return (
  {/* */}
  <nav style={{ margin: 10 }}>
      <NavLink to='/' activeClassName='active'>
          Home
      </NavLink>

      <NavLink to='/about' activeClassName='active'>
          About
      </NavLink>
  </nav>

 {/* */}
)
Enter fullscreen mode Exit fullscreen mode

回到浏览器,打开如下所示的开发工具,您会注意到,首先,该Home路线有一个类名active

SS7

尝试导航到该About路线并观察会发生什么。

SS8

在导航到About路由时,您是否注意到 active 类名也添加到了相应的路由中?但是,Home即使 URL 与 匹配,路由仍然保留着 active 类名/about。为什么?

其工作方式NavLink与 React Router API 中的 Route 组件基本相似。为了确保只有一个路由具有 active 类状态,请尝试修改导航菜单中的 home 路由,如下所示。

// App.js

<NavLink to='/' exact activeClassName='active'>
    Home
</NavLink>
Enter fullscreen mode Exit fullscreen mode

这次您将获得所需的输出。

SS9

向路由添加参数

在本节中,您将学习如何基于查询参数(例如)创建和管理动态路由:id。我们首先在文件中创建一个静态数组App.js,作为模拟数据。

这个想法是为了演示一个路由,/posts它显示来自数组的所有帖子。但是,数组中的每篇帖子都会有一个 id 或唯一标识符。使用该唯一标识符,您将通过编写 URL 的逻辑(例如,/posts/:idwhere:id将由帖子的特定 id 表示)来理解动态内容渲染的概念。

首先,让我们在名为 的新组件文件中添加一堆模拟帖子components/posts.js

// Posts.js
import React from "react"
import "../App.css"

class Posts extends React.Component {
    state = {
        posts: [
            { id: 1, title: "Hello Blog World!" },
            { id: 2, title: "My second post" },
            { id: 3, title: "What is React Router?" }
        ]
    }

    render() {
        return (
            <div className='posts'>
                <h1>Posts List</h1>
            </div>
        )
    }
}

export default Posts
Enter fullscreen mode Exit fullscreen mode

为了简洁起见,在文件中添加了与上述对应的样式App.css

.posts ul {
    list-style: none;
    margin: 0;
    margin-bottom: 20px;
    padding: 0;
}

.posts ul li {
    padding: 10px;
}

.posts a {
    text-decoration: none;
}
Enter fullscreen mode Exit fullscreen mode

现在,将新创建的组件导入到App.js其他路由已经存在的地方。

//App.js
// ...
import Posts from "./components/Posts"

function App() {
    return (
        <Router>
            <div>
                <nav style={{ margin: 10 }}>
                    <NavLink to='/' exact activeClassName='active'>
                        Home
                    </NavLink>
                    <NavLink to='/about' activeClassName='active'>
                        About
                    </NavLink>
                    <NavLink to='/posts' activeClassName='active'>
                        Posts
                    </NavLink>
                </nav>
                <Route path='/' exact component={Home} />
                <Route path='/about' component={About} />
                <Route path='/posts' component={Posts} />
            </div>
        </Router>
    )
}

export default App
Enter fullscreen mode Exit fullscreen mode

现有的导航菜单有一条新路线,称为帖子。

SS10

打开Posts.js以呈现帖子列表,并在 Web 浏览器中的当前位置匹配时将其显示为列表/posts

import React from "react"
import { Link, Route } from "react-router-dom"
import "../App.css"

function Child({ match }) {
    return (
        <div>
            <h3>ID: {match.params.id}</h3>
        </div>
    )
}

class Posts extends React.Component {
    state = {
        posts: [
            {
                id: 1,
                title: "Hello Blog World!"
            },
            {
                id: 2,
                title: "My second post"
            },
            {
                id: 3,
                title: "What is React Router?"
            }
        ]
    }

    render() {
        const { posts } = this.state
        return (
            <div className='posts'>
                <h1>Posts List</h1>
                <ul>
                    {posts.map(post => (
                        <li key={post.id}>
                            <Link to={`/posts/${post.id}`}>{post.title}</Link>
                        </li>
                    ))}
                </ul>
                <Route path='/posts/:id' component={Child} />
            </div>
        )
    }
}

export default Posts
Enter fullscreen mode Exit fullscreen mode

此外,该Child组件还会读取来自 URL 参数的任何内容,例如,在上面的例子中,读取id每篇帖子的 。一个match对象包含有关 如何<Route path>匹配 URL 的信息,因此,在我们的例子中,就是每篇帖子的 ID。

SS11

结论

希望您现在已经熟悉了 React Router 库的基本工作原理。它是一个功能强大的库,可以帮助您构建更好的 React 应用。如果您想了解更多关于 React Router 的信息,请访问其官方文档


这篇文章最初发表于此处

我经常撰写 Nodejs、Reactjs 和 React Native 相关的代码。您可以访问我的amanhimself.dev页面,也可以订阅我的每周新闻邮件,这样就能直接在邮箱里收到我的所有教程和更新💌。

文章来源:https://dev.to/amanhimself/using-react-router-to-optimize-single-page-applications-4mim
PREV
去抖动和 Web 性能
NEXT
如何使用 React Hooks 添加暗模式功能