共计 2982 个字符,预计需要花费 8 分钟才能阅读完成。
大家好,我卡颂。
React
技术栈的一大劣势在于 —— 社区凋敝,你业务中须要实现的性能根本都能找到对应的开源库。
但凋敝也有不好的一面 —— 要实现同样的性能,有太多抉择,到底选哪个?
本文要介绍一个 12.7k 的开源我的项目 —— Bulletproof React
这个我的项目为构建 简洁、弱小、可扩大的前端我的项目架构 的方方面面给出了倡议。
欢送退出人类高质量前端框架群,带飞
Bulletproof React 是什么
Bulletproof React
与咱们常见的脚手架(比方 CRA
)不同,后者的作用是 依据模版创立一个新我的项目。
而前者蕴含一个残缺的 React
全栈论坛我的项目:
作者通过这个我的项目举例,展现了与 我的项目架构 相干的 13 个方面的内容,比方:
- 文件目录该如何组织
- 工程化配置有什么举荐
- 写业务组件时该怎么标准
- 怎么做状态治理
API
层如何设计- 等等 ……
限于篇幅无限,本文介绍其中局部观点。
不晓得这些观点你是否认同呢?
文件目录如何组织
我的项目举荐如下目录模式:
src
|
+-- assets # 动态资源
|
+-- components # 公共组件
|
+-- config # 全局配置
|
+-- features # 个性
|
+-- hooks # 专用 hooks
|
+-- lib # 二次导出的第三方库
|
+-- providers # 利用中所有 providers
|
+-- routes # 路由配置
|
+-- stores # 全局状态 stores
|
+-- test # 测试工具、mock 服务器
|
+-- types # 全局类型文件
|
+-- utils # 通用工具函数
其中,features
目录与 components
目录的区别在于:
components
寄存全局专用的组件,而 features
寄存 业务相干个性。
比方我要开发 评论 模块,评论 作为一个个性,与他相干的所有内容都存在于 features/comments
目录下。
评论 模块中须要输入框,输入框这个通用组件来自于 components
目录。
所有 个性相干 的内容都会收敛到 features
目录下,具体包含:
src/features/xxx-feature
|
+-- api # 与个性相干的申请
|
+-- assets # 与个性相干的动态资源
|
+-- components # 与个性相干的组件
|
+-- hooks # 与个性相干的 hooks
|
+-- routes # 与个性相干的路由
|
+-- stores # 与个性相干的状态 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 寄存在全局 hooks 目录),以 features
目录作为 相干代码的汇合 可能无效避免我的项目体积增大后代码组织凌乱的状况。
怎么做状态治理
我的项目中并不是所有状态都须要保留在 中心化的 store中,须要依据状态类型区别对待。
组件状态
对于组件的部分状态,如果只有组件本身以及他的子孙组件须要这部分状态,那么能够用 useState
或useReducer
保留他们。
利用状态
与利用交互相干的状态,比方 关上弹窗 、 告诉 、 扭转黑夜模式 等,应该遵循 将状态尽可能凑近应用他的组件 的准则,不要什么状态都定义为 全局状态。
以 Bulletproof React
中的示例我的项目举例,首先定义 告诉相干的状态:
// bulletproof-react/src/stores/notifications.ts
export const useNotificationStore = create<NotificationsStore>((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.tsx
import {useNotificationStore} from '@/stores/notifications';
import {Notification} from './Notification';
export const Notifications = () => {const { notifications, dismissNotification} = useNotificationStore();
return (
<div
>
{notifications.map((notification) => (
<Notification
key={notification.id}
notification={notification}
onDismiss={dismissNotification}
/>
))}
</div>
);
};
这里应用的状态管理工具是zustand
,除此之外还有很多可选计划:
context
+hooks
redux
+redux toolkit
mobx
constate
jotai
recoil
xstate
这些计划各有特点,但他们都是为了解决 利用状态。
服务端缓存状态
对于从服务端申请而来,缓存在前端的数据,尽管能够用上述解决 利用状态 的工具解决,但 服务端缓存状态 相比于 利用状态 ,还波及到 缓存生效 、 序列化数据 等问题。
所以最好用专门的工具解决,比方:
react-query - REST
+GraphQL
swr - REST
+GraphQL
apollo client
–GraphQL
urql
–GraphQl
表单状态
表单数据须要辨别 受控 与非受控 ,表单自身还有很多逻辑须要解决(比方 表单校验),所以也举荐用专门的库解决这部分状态,比方:
React Hook Form
Formik
React Final Form
URL 状态
URL
状态包含:
url params
(/app/${dynamicParam})query params
(/app?dynamicParam=1)
这部分状态通常是路由库解决,比方react-router-dom
。
总结
本文节选了局部 Bulletproof React
中举荐的计划,有没有让你认可的观点呢?
欢送在评论区交换我的项目架构中的最佳实际。