将你的 React 应用组织成模块
第一次在这里发帖,也是我多年的读者。觉得是时候回馈一下了。
我从事软件开发八年,最后两年一直在做 React 开发。之前用过原生 JavaScript 和 jQuery,但不得不说,我爱上了 React。
这篇文章将详细介绍我们如何组织我们的 React 应用程序。
这篇文章还假设您已经知道如何设置和使用 React(即这不是入门文章)。
让我们开始吧!
简介
我厌倦了待办事项 - 因此我们的虚构 shell 应用程序是游戏工作室的错误跟踪器,允许 alpha 和 beta 测试人员报告错误。
它有四个模块:仪表板、游戏、用户、分析。
这种方法的优点在于,父应用对子模块没有任何具体的了解。它只知道自己 拥有 哪些模块。每个模块管理自己的位置和数据。你无需在父应用的任何地方添加 <Route />
或 <Link></Link>
- 这些都由子应用定义。
这篇文章的代码在 GitHub 上。
入门
让我们开始实际的编码吧!
如果你没有 create-react-app,请使用 安装它 npm install -g create-react-app
。然后...
create-react-app dev-react-modules
cd dev-react-modules
npm install react-router-dom --save
yarn start
我不会详细说明所应用的样式,您可以在 GitHub repo 中查看。
创建模块
在 src 文件夹下,我们首先创建模块结构。它看起来像这样:
在每个模块的文件夹中,添加一个 index.js
src\modules\Analytics\index.js
import React from ' react ' ;
const Analytics = () => (
< div > Analytics Module</ div >
);
export default {
routeProps : {
path : ' /analytics ' ,
component : Analytics
},
name : ' Analytics ' ,
}
Enter fullscreen mode
Exit fullscreen mode
src\modules\Dashboard\index.js
import React from ' react ' ;
const Dashboard = () => (
< div > Dashboard Module</ div >
);
export default {
routeProps : {
path : ' / ' ,
exact : true ,
component : Dashboard ,
},
name : ' Dashboard ' ,
};
Enter fullscreen mode
Exit fullscreen mode
src\modules\游戏\index.js
import React from ' react ' ;
const Games = () => (
< div > Games Module</ div >
);
export default {
routeProps : {
path : ' /games ' ,
component : Games ,
},
name : ' Games ' ,
};
Enter fullscreen mode
Exit fullscreen mode
src\modules\Users\index.js
import React from ' react ' ;
const Users = () => (
< div > Users Module</ div >
);
export default {
routeProps : {
path : ' /users ' ,
component : Users ,
},
name : ' Users ' ,
};
Enter fullscreen mode
Exit fullscreen mode
这里没什么特别的,我们创建了模块及其默认导出。但我们不是 只导出一个组件 (让父组件自行协调),而是导出 模块存在所需的一切 。这可以扩展到包括模块主题、导航图标、所需权限等等……
我喜欢这个功能,因为我不需要改变父级来添加模块。我只需要……添加一个模块。
让我们分解一下导出,我在下面添加了一些评论。
export default {
routeProps : { // This gets passed straight to react-router
path : ' /users ' , // Where the module lives in the nav hierarchy
component : Users , // The actual component itself
},
name : ' Users ' , // The name of the module
};
Enter fullscreen mode
Exit fullscreen mode
你可以把导出结构想象成父模块和子模块之间的契约。父模块说,我不关心有多少个模块,我只需要这些东西来渲染你。
现在我们需要导出所有这些模块。在 modules 文件夹中,创建一个 index.js 文件。
src\modules\index.js
import Analytics from ' ./Analytics ' ;
import Dashboard from ' ./Dashboard ' ;
import Games from ' ./Games ' ;
import Users from ' ./Users ' ;
export default [
Dashboard ,
Analytics ,
Games ,
Users
];
Enter fullscreen mode
Exit fullscreen mode
这里我们导出的是模块 列表 。这正是父级所需要的。
创建家长应用程序
现在我们的子模块都已完成,让我们将它们全部整合到主 App.js 中。
src\App.js
import React from ' react ' ;
import { useState } from ' react ' ;
import { BrowserRouter as Router , Route , Link } from " react-router-dom " ;
import logo from ' ./logo.svg ' ;
import ' ./App.css ' ;
import modules from ' ./modules ' ; // All the parent knows is that it has modules ...
function App () {
const [ currentTab , setCurrentTab ] = useState ( ' dashboard ' );
return (
< Router >
< div className = "App" >
< header className = "App-header" >
< img src = { logo } className = "App-logo" alt = "logo" />
< ul className = "App-nav" >
{ modules . map ( module => ( // with a name, and routes
< li key = { module . name } className = { currentTab === module . name ? ' active ' : '' } >
< Link to = { module . routeProps . path } onClick = { () => setCurrentTab ( module . name ) } > { module . name } </ Link >
</ li >
)) }
</ ul >
</ header >
< div className = "App-content" >
{ modules . map ( module => (
< Route { ... module . routeProps } key = { module . name } />
)) }
</ div >
</ div >
</ Router >
);
}
Enter fullscreen mode
Exit fullscreen mode
让我们来分析一下。
import modules from './modules';
正如我之前所说,父级只需要知道它有模块。在这里,我们导入它们。
< ul className = "App-nav" >
{ modules . map ( module => (
< li key = { module . name } className = { currentTab === module . name ? ' active ' : '' } >
< Link to = { module . routeProps . path } onClick = { () => setCurrentTab ( module . name ) } > { module . name } </ Link >
</ li >
)) }
</ ul >
Enter fullscreen mode
Exit fullscreen mode
在这里,父级知道模块有一个名称和一个链接(因为它是一个合同,记得吗?),所以它可以动态构建导航菜单。
< div className = "App-content" >
{ modules . map ( module => (
< Route { ... module . routeProps } key = { module . name } />
)) }
</ div >
Enter fullscreen mode
Exit fullscreen mode
这里,父级也知道模块有一个带组件的路由,因此它可以动态地渲染 <Route />
。
现在您有一个自组织、模块化的 React 应用程序。
但请稍等,还有更多!
添加新模块
我们遗漏了错误跟踪器的一个关键模块:错误。
我们的新结构的优点在于,我所要做的就是将新模块添加到导出列表中。
src\modules\Bugs\index.js
import React from ' react ' ;
const Bugs = () => (
< div > Bugs Module</ div >
);
export default {
routeProps : {
path : ' /bugs ' ,
component : Bugs ,
},
name : ' Bugs ' ,
};
Enter fullscreen mode
Exit fullscreen mode
src\modules\index.js
import Analytics from ' ./Analytics ' ;
import Bugs from ' ./Bugs ' ; // added
import Dashboard from ' ./Dashboard ' ;
import Games from ' ./Games ' ;
import Users from ' ./Users ' ;
export default [
Dashboard ,
Games ,
Bugs , // added
Users ,
Analytics ,
];
Enter fullscreen mode
Exit fullscreen mode
结论
我已经使用这个结构好几年了,非常喜欢它。它在我们的应用中扩展了不少,但我想让这篇文章保持简洁。
这也并非我的功劳。几年前刚开始使用 React 时,我很幸运能与一位资深 React 专家共事。他教会了我这种结构(并且一直在教我良好的 React 实践)。我喜欢向其他开发者学习!
有什么想法、问题或建议吗?你是如何组织你的 React 项目的?
鏂囩珷鏉ユ簮锛�https://dev.to/jack/organizing-your-react-app-into-modules-d6n