使用 Vite 和基于文件的路由简化 React 中的路由
介绍
开发人员最喜欢的事情之一就是改进重复性工作的流程,尤其是在处理需求相对简单的事情时,例如在应用程序中定义路由。
在今天的文章中,我们将创建一个结构,以便能够动态地定义应用程序的路由,同时考虑到特定文件夹中的文件。
假定知识
以下信息将很有帮助:
- React基础知识
- React Router 的基础知识
- 维特的基本知识
入门
第一步是启动应用程序引导程序。
项目设置
在终端中运行以下命令:
yarn create vite app-router --template react
cd app-router
现在我们可以安装必要的依赖项了:
yarn add react-router-dom
今天的例子就讲到这里,现在我们需要进入下一步。
引导文件夹结构
假设我们的pages/文件夹结构如下:
|-- pages/
|-- dashboard/
|--$id.jsx
|-- analytics.jsx
|-- index.jsx
|-- about.jsx
|-- index.jsx
从以上片段我们可以得出以下结论:
- 命名空间
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 });
// ...
上面的代码片段旨在加载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;
}
// ...
}
// ...
加载完文件夹中的所有模块后,我们创建一个名为 `<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/, "");
// ...
}
// ...
路径规范化后,我们可以将目前已有的数据添加到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,
});
}
// ...
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;
结论
无论你是将这些信息运用到现有项目中,还是仅仅出于兴趣尝试一下,我都希望这篇文章对你有所帮助。
如果您在文章中发现任何错误,请在评论区留言告知。如果您想查看本文的源代码,可以在下方链接的 GitHub 代码库中找到。
文章来源:https://dev.to/franciscomendes10866/file-based-routing-using-vite-and-react-router-3fdo