当前位置: 首页 > Web前端 > HTML

一个简洁、强大、可扩展的前端项目架构是什么样的?

时间:2023-03-28 00:58:42 HTML

大家好,我是Kason。React技术栈的优势之一就是社区繁荣,你在业务中需要实现的功能基本都能找到对应的开源库。但繁荣也有不利的一面——实现同样的功能,选择太多,该选哪个?本文将介绍一个12.7k的开源项目——BulletproofReact,该项目给出了构建简单、强大、可扩展的前端项目架构的各个方面的建议。欢迎加入人类优质前端框架群,什么是BulletproofReact?BulletproofReact不同于我们常见的脚手架(比如CRA),它是用来基于模板创建新项目的。前者包括一个完整的React全栈论坛项目:作者以该项目为例,展示了与项目架构相关的13个方面,如:文件目录如何组织、工程配置、写业务时推荐什么成分?如何规范状态管理API层的设计方式等等……限于篇幅,本文介绍其中的一些观点。你同意这些观点吗?文件目录如何组织项目推荐如下目录格式:src|+--assets#静态资源|+--components#公共组件|+--config#全局配置|+--features#特性|+--hooks#公共钩子|+--lib#二次导出的第三方库|+--providers#应用中的所有provider|+--routes#路由配置|+--stores#全局statestores|+--test#测试工具,mockServer|+--types#全局类型文件|+--utils#通用工具函数其中features目录和components目录的区别是components存放全局公共组件,features存放业务-相关的功能。比如我想开发一个评论模块。评论是一个特征,所有和他相关的内容都存在于features/comments目录下。评论模块中需要输入框,输入框的常用组件来自components目录。所有与特性相关的内容都会汇聚到features目录下,包括:src/features/xxx-feature|+--api#特性相关的请求|+--assets#特性相关的静态资源|+--components#Feature-相关组件|+--hooks#特性相关的钩子|+--routes#特性相关的路由|+--stores#特性相关的状态存储|+--types#特性相关的类型声明|+--utils#特征相关的实用函数|+--index.ts#所有入口特征导出的内容只能通过统一的入口调用,例如:import{CommentBar}from"@/features/comments"而不是:import{CommentBar}from"@/features/comments/components/CommentBar这可以通过配置ESLint来实现:{rules:{'no-restricted-imports':['error',{patterns:['@/features/*/*'],},],//...其他配置}}与在全局目录中以平面形式存储特征相关的内容(如在全局hooks目录中存储特征钩子)相比,u将features目录作为相关代码的集合,可以有效防止项目规模增大后代码组织混乱。如何做状态管理项目中并不是所有的状态都需要集中存储,需要根据状态类型区别对待。组件状态对于组件的局部状态,如果只有组件本身及其后代需要这部分状态,可以用useState或useReducer保存。应用状态与应用交互有关,比如打开弹窗、通知、更改深色模式等,应遵循状态尽可能靠近使用它的组件的原则,不要将所有状态定义为全局状态。以BulletproofReact中的示例工程为例,首先定义通知相关的状态://bulletproof-react/src/stores/notifications.tsexportconstuseNotificationStore=create((set)=>({notifications:[],addNotification:(notification)=>set((state)=>({notifications:[...state.notifications,{id:nanoid(),...notification}],})),dismissNotification:(id)=>set((state)=>({notifications:state.notifications.filter((notification)=>notification.id!==id),})),}));然后引用任何使用通知相关状态useNotificationStore的地方,例如://bulletproof-react/src/components/Notifications/Notifications.tsximport{useNotificationStore}from'@/stores/notifications';从'./Notification'导入{Notification};exportconstNotifications=()=>{const{notifications,dismissNotification}=useNotificationStore();返回(

{notifications.map((notification)=>())}
);};这里使用的状态管理工具是zustand,还有很多方案:context+hooksredux+reduxtoolkitmobxconstatejotairecoilxstate这些方案各有特点,但都是针对应用状态的处理。与应用状态相比,还涉及到缓存失效、序列化数据等问题。所以最好使用专门的工具,比如:react-query-REST+GraphQLswr-REST+GraphQLapolloclient-GraphQLurql-GraphQlformstate表单数据需要区分受控和非受控,表单本身还是有很多要处理的逻辑(比如Form验证),所以也推荐使用专门的库来处理这部分状态,比如:ReactHookFormFormikReactFinalFormURLstateURLstateincludes:urlparams(/app/${dynamicParam})queryparams(/app?dynamicParam=1)这部分状态通常由路由库处理,比如react-router-dom。小结本文摘录了BulletproofReact中推荐的一些解决方案。有什么观点是你认同的?欢迎在评论区交流项目架构的最佳实践。