发布于 2026-01-06 0 阅读
0

使用 Vite 和基于文件的路由简化 React 中的路由

使用 Vite 和基于文件的路由简化 React 中的路由

介绍

开发人员最喜欢的事情之一就是改进重复性工作的流程,尤其是在处理需求相对简单的事情时,例如在应用程序中定义路由。

在今天的文章中,我们将创建一个结构,以便能够动态地定义应用程序的路由,同时考虑到特定文件夹中的文件。

假定知识

以下信息将很有帮助:

  • React基础知识
  • React Router 的基础知识
  • 维特的基本知识

入门

第一步是启动应用程序引导程序。

项目设置

在终端中运行以下命令:

yarn create vite app-router --template react
cd app-router
Enter fullscreen mode Exit fullscreen mode

现在我们可以安装必要的依赖项了:

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

今天的例子就讲到这里,现在我们需要进入下一步。

引导文件夹结构

假设我们的pages/文件夹结构如下:

|-- pages/
   |-- dashboard/
      |--$id.jsx
      |-- analytics.jsx
      |-- index.jsx
   |-- about.jsx
   |-- index.jsx  
Enter fullscreen mode Exit fullscreen mode

从以上片段我们可以得出以下结论:

  • 命名空间index对应于路由/子路由的根;
  • dashboard路线有多条子路线;
  • $符号表示该路径需要一个参数。

考虑到这一点,我们可以开始讨论 Vite 的一个神奇功能,称为Glob Import,它能够导入多个模块,同时考虑到文件系统。

设置路由器抽象

在开始修改代码之前,我建议先创建一个模式,您可以参考已知的项目方法和/或框架。

我的建议是,这样可以更轻松地定义路由器的结构,例如,应该将哪个组件分配给哪个路由?是否可以添加错误边界?诸如此类的问题很重要。

为了演示其工作原理,让我们App.jsx从下面开始编辑:

// @/src/App.jsx
import { createBrowserRouter, RouterProvider } from "react-router-dom";

const pages = import.meta.glob("./pages/**/*.jsx", { eager: true });

// ...
Enter fullscreen mode Exit fullscreen mode

上面的代码片段旨在加载pages/文件夹中存在的所有模块。该glob()函数将返回一个对象,其键对应于每个模块的路径,值则包含模块导出的属性。

// @/src/App.jsx
import { createBrowserRouter, RouterProvider } from "react-router-dom";

const pages = import.meta.glob("./pages/**/*.jsx", { eager: true });

const routes = [];
for (const path of Object.keys(pages)) {
  const fileName = path.match(/\.\/pages\/(.*)\.jsx$/)?.[1];
  if (!fileName) {
    continue;
  }

  // ...
}

// ...
Enter fullscreen mode Exit fullscreen mode

加载完文件夹中的所有模块后,我们创建一个名为 `<modules>` 的数组routes,其中包含一个对象列表,这些对象具有以下属性:

  • path- 我们想要注册的路径;
  • Element- 要分配给该路径的 React 组件;
  • loader- 负责获取数据的函数(可选);
  • action- 负责提交表单数据的函数(可选);
  • ErrorBoundary- React 组件,负责在路由级别捕获 JavaScript 错误(可选)。

我们需要获取文件名。如果文件名未定义,则直接忽略并处理下一个文件。但是,如果文件名已定义,则需要对其进行规范化,以便注册路由。

// @/src/App.jsx
import { createBrowserRouter, RouterProvider } from "react-router-dom";

const pages = import.meta.glob("./pages/**/*.jsx", { eager: true });

const routes = [];
for (const path of Object.keys(pages)) {
  const fileName = path.match(/\.\/pages\/(.*)\.jsx$/)?.[1];
  if (!fileName) {
    continue;
  }

  const normalizedPathName = fileName.includes("$")
    ? fileName.replace("$", ":")
    : fileName.replace(/\/index/, "");

  // ...
}

// ...
Enter fullscreen mode Exit fullscreen mode

路径规范化后,我们可以将目前已有的数据添加到routes数组中,记住分配给路由的组件必须是 `<component>`,export default而所有其他函数(包括错误边界)都必须是 `<component>` export。像这样:

// @/src/App.jsx
import { createBrowserRouter, RouterProvider } from "react-router-dom";

const pages = import.meta.glob("./pages/**/*.jsx", { eager: true });

const routes = [];
for (const path of Object.keys(pages)) {
  const fileName = path.match(/\.\/pages\/(.*)\.jsx$/)?.[1];
  if (!fileName) {
    continue;
  }

  const normalizedPathName = fileName.includes("$")
    ? fileName.replace("$", ":")
    : fileName.replace(/\/index/, "");

  routes.push({
    path: fileName === "index" ? "/" : `/${normalizedPathName.toLowerCase()}`,
    Element: pages[path].default,
    loader: pages[path]?.loader,
    action: pages[path]?.action,
    ErrorBoundary: pages[path]?.ErrorBoundary,
  });
}

// ...
Enter fullscreen mode Exit fullscreen mode

routes有了必要的数据,我们现在可以通过遍历数组并在路由提供程序中为路由定义 React Router 中的每个路由。就像这样:

// @/src/App.jsx
import { createBrowserRouter, RouterProvider } from "react-router-dom";

// ...

const router = createBrowserRouter(
  routes.map(({ Element, ErrorBoundary, ...rest }) => ({
    ...rest,
    element: <Element />,
    ...(ErrorBoundary && { errorElement: <ErrorBoundary /> }),
  }))
);

const App = () => {
  return <RouterProvider router={router} />;
};

export default App;
Enter fullscreen mode Exit fullscreen mode

结论

无论你是将这些信息运用到现有项目中,还是仅仅出于兴趣尝试一下,我都希望这篇文章对你有所帮助。

如果您在文章中发现任何错误,请在评论区留言告知。如果您想查看本文的源代码,可以在下方链接的 GitHub 代码库中找到。

GitHub 仓库

文章来源:https://dev.to/franciscomendes10866/file-based-routing-using-vite-and-react-router-3fdo