MK
摩柯社区 - 一个极简的技术知识社区
AI 面试

React Router 基础入门与安装

2022-05-211.2k 阅读

1. React Router 简介

React Router 是用于在 React 应用中进行路由管理的核心库。在单页应用(SPA)的开发中,路由起着至关重要的作用。它使得应用能够根据不同的 URL 展示不同的 UI 内容,为用户提供类似于多页应用的导航体验,同时又不会因为页面的重新加载而导致性能问题。

React Router 提供了声明式的路由语法,这意味着开发者可以像声明 React 组件一样声明应用的路由结构。这种声明式的方式使得路由配置更加直观,易于理解和维护。例如,通过简单的配置,我们可以指定当 URL 为 /home 时,展示 Home 组件;当 URL 为 /about 时,展示 About 组件。

2. 安装 React Router

在开始使用 React Router 之前,我们需要将其安装到项目中。React Router 有不同的版本,目前较新的版本是 React Router v6。安装步骤如下:

2.1 创建 React 项目(如果尚未创建)

如果还没有 React 项目,可以使用 create - react - app 工具快速创建一个新的 React 项目。首先确保你已经全局安装了 create - react - app

npm install -g create - react - app

然后创建项目:

create - react - app my - react - app
cd my - react - app

2.2 安装 React Router

在项目目录下,使用 npmyarn 安装 React Router:

# 使用 npm
npm install react - router - dom
# 使用 yarn
yarn add react - router - dom

这里我们安装的是 react - router - dom,它是 React Router 用于 web 应用的特定版本。如果是开发 React Native 应用,则需要安装 react - router - native

3. 基本路由配置

安装完成后,我们就可以开始配置基本路由了。以下是一个简单的示例,展示如何在 React 应用中配置两个基本路由:HomeAbout

3.1 创建组件

首先,创建 HomeAbout 组件。在 src 目录下,创建 components 文件夹,并在其中创建 Home.jsAbout.js 文件。

Home.js

import React from'react';

const Home = () => {
    return (
        <div>
            <h1>Home Page</h1>
            <p>This is the home page of our React application.</p>
        </div>
    );
};

export default Home;

About.js

import React from'react';

const About = () => {
    return (
        <div>
            <h1>About Page</h1>
            <p>This is the about page where you can learn more about our application.</p>
        </div>
    );
};

export default About;

3.2 配置路由

src 目录下的 App.js 文件中,导入并配置路由。在 React Router v6 中,主要使用 BrowserRouterRoutesRoute 组件。

import React from'react';
import { BrowserRouter as Router, Routes, Route } from'react - router - dom';
import Home from './components/Home';
import About from './components/About';

function App() {
    return (
        <Router>
            <Routes>
                <Route path="/" element={<Home />} />
                <Route path="/about" element={<About />} />
            </Routes>
        </Router>
    );
}

export default App;

在上述代码中:

  • BrowserRouter 是整个应用路由的顶层容器,它会监听浏览器地址栏的变化,并根据路由配置渲染相应的组件。这里我们使用了别名 Router,这是一种常见的写法。
  • Routes 组件用于定义一组路由。它会根据当前 URL 匹配到合适的 Route 并渲染对应的组件。
  • Route 组件定义了具体的路由规则。path 属性指定了 URL 路径,element 属性指定了该路径对应的要渲染的 React 组件。

4. 嵌套路由

在实际应用中,我们经常会遇到嵌套路由的情况。例如,一个博客应用可能有文章列表页面,每个文章又有自己的详情页面,而且这些详情页面可能还包含评论、相关文章等子页面。

4.1 创建嵌套组件

假设我们有一个 Blog 组件,它包含文章列表,并且每个文章有详情页。我们先创建 Blog 组件和 Article 组件。

Blog.js

import React from'react';

const Blog = () => {
    return (
        <div>
            <h1>Blog Page</h1>
            <p>This is the blog page with a list of articles.</p>
        </div>
    );
};

export default Blog;

Article.js

import React from'react';

const Article = () => {
    return (
        <div>
            <h1>Article Page</h1>
            <p>This is the page for a specific article.</p>
        </div>
    );
};

export default Article;

4.2 配置嵌套路由

App.js 中配置嵌套路由:

import React from'react';
import { BrowserRouter as Router, Routes, Route } from'react - router - dom';
import Home from './components/Home';
import About from './components/About';
import Blog from './components/Blog';
import Article from './components/Article';

function App() {
    return (
        <Router>
            <Routes>
                <Route path="/" element={<Home />} />
                <Route path="/about" element={<About />} />
                <Route path="/blog" element={<Blog />}>
                    <Route path=":articleId" element={<Article />} />
                </Route>
            </Routes>
        </Router>
    );
}

export default App;

在上述代码中,/blog 路由下嵌套了一个动态路由 :articleId。这里的 :articleId 是一个动态参数,它可以匹配任何字符串。例如,/blog/123 会匹配到这个路由,并且可以通过 useParams 钩子函数获取到 articleId 的值为 123

5. 路由导航

路由配置完成后,我们需要提供导航链接,让用户能够在不同的路由之间切换。在 React Router 中,可以使用 Link 组件来创建导航链接。

5.1 使用 Link 组件

App.js 中添加导航链接:

import React from'react';
import { BrowserRouter as Router, Routes, Route, Link } from'react - router - dom';
import Home from './components/Home';
import About from './components/About';
import Blog from './components/Blog';
import Article from './components/Article';

function App() {
    return (
        <Router>
            <div>
                <nav>
                    <ul>
                        <li><Link to="/">Home</Link></li>
                        <li><Link to="/about">About</Link></li>
                        <li><Link to="/blog">Blog</Link></li>
                    </ul>
                </nav>
                <Routes>
                    <Route path="/" element={<Home />} />
                    <Route path="/about" element={<About />} />
                    <Route path="/blog" element={<Blog />}>
                        <Route path=":articleId" element={<Article />} />
                    </Route>
                </Routes>
            </div>
        </Router>
    );
}

export default App;

在上述代码中,我们在 nav 标签内使用 Link 组件创建了到 HomeAboutBlog 页面的链接。Link 组件的 to 属性指定了链接的目标路径。

5.2 NavLink 组件

NavLinkLink 的一个增强版本,它可以在链接对应的路由被激活时添加特定的样式。例如,我们可以让当前激活的导航链接有不同的颜色。

import React from'react';
import { BrowserRouter as Router, Routes, Route, NavLink } from'react - router - dom';
import Home from './components/Home';
import About from './components/About';
import Blog from './components/Blog';
import Article from './components/Article';

function App() {
    return (
        <Router>
            <div>
                <nav>
                    <ul>
                        <li><NavLink to="/" style={({ isActive }) => ({ color: isActive? 'blue' : 'black' })}>Home</NavLink></li>
                        <li><NavLink to="/about" style={({ isActive }) => ({ color: isActive? 'blue' : 'black' })}>About</NavLink></li>
                        <li><NavLink to="/blog" style={({ isActive }) => ({ color: isActive? 'blue' : 'black' })}>Blog</NavLink></li>
                    </ul>
                </nav>
                <Routes>
                    <Route path="/" element={<Home />} />
                    <Route path="/about" element={<About />} />
                    <Route path="/blog" element={<Blog />}>
                        <Route path=":articleId" element={<Article />} />
                    </Route>
                </Routes>
            </div>
        </Router>
    );
}

export default App;

在上述代码中,NavLinkstyle 属性接受一个函数,该函数根据 isActive 参数来决定是否应用特定的样式。当 isActivetrue 时,即当前链接对应的路由被激活时,文字颜色变为蓝色。

6. 获取路由参数

在动态路由中,获取路由参数是非常常见的需求。例如,在文章详情页,我们需要根据文章的 ID 获取具体的文章内容。在 React Router v6 中,可以使用 useParams 钩子函数来获取路由参数。

6.1 使用 useParams

Article.js 组件中获取 articleId 参数:

import React from'react';
import { useParams } from'react - router - dom';

const Article = () => {
    const { articleId } = useParams();
    return (
        <div>
            <h1>Article Page - {articleId}</h1>
            <p>This is the page for article with ID: {articleId}</p>
        </div>
    );
};

export default Article;

在上述代码中,通过 useParams 钩子函数获取到 articleId 参数,并将其显示在页面上。

7. 路由重定向

有时候,我们需要将用户从一个路由重定向到另一个路由。例如,当用户访问一个旧的 URL 时,我们希望将其重定向到新的 URL。在 React Router v6 中,可以使用 Navigate 组件进行重定向。

7.1 使用 Navigate 组件

假设我们有一个旧的 /old - home 路由,现在希望将其重定向到 / 路由。在 App.js 中配置:

import React from'react';
import { BrowserRouter as Router, Routes, Route, Navigate } from'react - router - dom';
import Home from './components/Home';
import About from './components/About';
import Blog from './components/Blog';
import Article from './components/Article';

function App() {
    return (
        <Router>
            <div>
                <nav>
                    <ul>
                        <li><NavLink to="/" style={({ isActive }) => ({ color: isActive? 'blue' : 'black' })}>Home</NavLink></li>
                        <li><NavLink to="/about" style={({ isActive }) => ({ color: isActive? 'blue' : 'black' })}>About</NavLink></li>
                        <li><NavLink to="/blog" style={({ isActive }) => ({ color: isActive? 'blue' : 'black' })}>Blog</NavLink></li>
                    </ul>
                </nav>
                <Routes>
                    <Route path="/" element={<Home />} />
                    <Route path="/about" element={<About />} />
                    <Route path="/blog" element={<Blog />}>
                        <Route path=":articleId" element={<Article />} />
                    </Route>
                    <Route path="/old - home" element={<Navigate to="/" replace />} />
                </Routes>
            </div>
        </Router>
    );
}

export default App;

在上述代码中,当用户访问 /old - home 时,Navigate 组件会将其重定向到 / 路由。replace 属性表示在重定向时使用 replaceState 而不是 pushState,这样在浏览器历史记录中不会留下 /old - home 的记录,用户点击后退按钮时不会回到 /old - home

8. 路由懒加载

随着应用的增长,打包后的文件大小也会增加。为了提高应用的加载性能,我们可以使用路由懒加载,即只有在需要的时候才加载相应的路由组件。在 React Router v6 中,可以结合 React.lazy 和 Suspense 来实现路由懒加载。

8.1 配置路由懒加载

App.js 中配置懒加载:

import React, { lazy, Suspense } from'react';
import { BrowserRouter as Router, Routes, Route, Navigate } from'react - router - dom';

const Home = lazy(() => import('./components/Home'));
const About = lazy(() => import('./components/About'));
const Blog = lazy(() => import('./components/Blog'));
const Article = lazy(() => import('./components/Article'));

function App() {
    return (
        <Router>
            <div>
                <nav>
                    <ul>
                        <li><NavLink to="/" style={({ isActive }) => ({ color: isActive? 'blue' : 'black' })}>Home</NavLink></li>
                        <li><NavLink to="/about" style={({ isActive }) => ({ color: isActive? 'blue' : 'black' })}>About</NavLink></li>
                        <li><NavLink to="/blog" style={({ isActive }) => ({ color: isActive? 'blue' : 'black' })}>Blog</NavLink></li>
                    </ul>
                </nav>
                <Routes>
                    <Route path="/" element={
                        <Suspense fallback={<div>Loading...</div>}>
                            <Home />
                        </Suspense>
                    } />
                    <Route path="/about" element={
                        <Suspense fallback={<div>Loading...</div>}>
                            <About />
                        </Suspense>
                    } />
                    <Route path="/blog" element={
                        <Suspense fallback={<div>Loading...</div>}>
                            <Blog />
                        </Suspense>
                    }>
                        <Route path=":articleId" element={
                            <Suspense fallback={<div>Loading...</div>}>
                                <Article />
                            </Suspense>
                        } />
                    </Route>
                    <Route path="/old - home" element={<Navigate to="/" replace />} />
                </Routes>
            </div>
        </Router>
    );
}

export default App;

在上述代码中,使用 React.lazy 函数将组件的导入延迟到实际需要渲染该组件时。Suspense 组件用于在组件加载时显示一个加载提示(这里是 Loading...)。

9. 路由守卫

路由守卫可以在路由切换之前或之后执行一些逻辑,例如验证用户是否登录、检查权限等。在 React Router v6 中,虽然没有像 Vue Router 那样直接提供路由守卫的功能,但我们可以通过一些自定义逻辑来实现类似的效果。

9.1 实现简单的路由守卫

假设我们有一个需要用户登录才能访问的 Dashboard 组件。我们可以创建一个自定义的 PrivateRoute 组件来实现路由守卫的功能。

PrivateRoute.js

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

const isLoggedIn = () => {
    // 这里可以实现实际的登录验证逻辑,例如检查 localStorage 中是否有 token
    return true;
};

const PrivateRoute = ({ children }) => {
    if (!isLoggedIn()) {
        return <Navigate to="/login" replace />;
    }
    return children;
};

export default PrivateRoute;

然后在 App.js 中使用 PrivateRoute

import React, { lazy, Suspense } from'react';
import { BrowserRouter as Router, Routes, Route, Navigate } from'react - router - dom';
import PrivateRoute from './components/PrivateRoute';

const Home = lazy(() => import('./components/Home'));
const About = lazy(() => import('./components/About'));
const Blog = lazy(() => import('./components/Blog'));
const Article = lazy(() => import('./components/Article'));
const Dashboard = lazy(() => import('./components/Dashboard'));

function App() {
    return (
        <Router>
            <div>
                <nav>
                    <ul>
                        <li><NavLink to="/" style={({ isActive }) => ({ color: isActive? 'blue' : 'black' })}>Home</NavLink></li>
                        <li><NavLink to="/about" style={({ isActive }) => ({ color: isActive? 'blue' : 'black' })}>About</NavLink></li>
                        <li><NavLink to="/blog" style={({ isActive }) => ({ color: isActive? 'blue' : 'black' })}>Blog</NavLink></li>
                        <li><NavLink to="/dashboard" style={({ isActive }) => ({ color: isActive? 'blue' : 'black' })}>Dashboard</NavLink></li>
                    </ul>
                </nav>
                <Routes>
                    <Route path="/" element={
                        <Suspense fallback={<div>Loading...</div>}>
                            <Home />
                        </Suspense>
                    } />
                    <Route path="/about" element={
                        <Suspense fallback={<div>Loading...</div>}>
                            <About />
                        </Suspense>
                    } />
                    <Route path="/blog" element={
                        <Suspense fallback={<div>Loading...</div>}>
                            <Blog />
                        </Suspense>
                    }>
                        <Route path=":articleId" element={
                            <Suspense fallback={<div>Loading...</div>}>
                                <Article />
                            </Suspense>
                        } />
                    </Route>
                    <Route path="/dashboard" element={
                        <PrivateRoute>
                            <Suspense fallback={<div>Loading...</div>}>
                                <Dashboard />
                            </Suspense>
                        </PrivateRoute>
                    } />
                    <Route path="/old - home" element={<Navigate to="/" replace />} />
                </Routes>
            </div>
        </Router>
    );
}

export default App;

在上述代码中,PrivateRoute 组件会检查用户是否登录(通过 isLoggedIn 函数)。如果用户未登录,就会将其重定向到 /login 路由。这样就实现了一个简单的路由守卫功能。

通过以上内容,我们对 React Router 的基础入门与安装进行了详细的介绍,包括基本路由配置、嵌套路由、路由导航、获取路由参数、路由重定向、路由懒加载以及路由守卫等重要知识点。这些内容是构建复杂 React 单页应用路由系统的基础,熟练掌握它们将有助于开发者创建出更加高效、用户体验良好的应用。