close
今天為各位帶來的是社區作者卡頌的文章,在這篇文章他介紹了一個開源項目,這個項目為構建簡潔、強大、可擴展的前端項目架構的方方面面給出了建議。一起來看看吧~

大家好,我卡頌。

React技術棧的一大優勢在於 —— 社區繁榮,你業務中需要實現的功能基本都能找到對應的開源庫。

但繁榮也有不好的一面 —— 要實現同樣的功能,有太多選擇,到底選哪個?

本文要介紹一個12.7k的開源項目 ——Bulletproof React

https://github.com/alan2207/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.tsexportconstuseNotificationStore=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.tsximport{useNotificationStore}from'@/stores/notifications';import{Notification}from'./Notification';exportconstNotifications=()=>{const{notifications,dismissNotification}=useNotificationStore();return(<div>{notifications.map((notification)=>(<Notificationkey={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中推薦的方案,有沒有讓你認可的觀點呢?

歡迎在評論區交流項目架構中的最佳實踐。

SegmentFault 思否社區小編說

自 2022-07-01 起 SegmentFault 思否公眾號改版啦!之後將陸續推出新的欄目和大家見面!(請拭目以待呀~❤)

在「社區精選」欄目中,我們將為廣大開發者推薦來自 SegmentFault 思否開發者社區的優質技術文章,這些文章全部出自社區中充滿智慧的技術創作者哦!

希望通過這一欄目,大家可以共同學習技術乾貨,GET 新技能和各種花式技術小 Tips。

歡迎越來越多的開發者加入創作者的行列,我們將持續甄選出社區中優質的內容推介給更多人,讓閃閃發光的技術創作者們走到聚光燈下,被更多人認識。


「社區精選」投稿郵箱:pr@segmentfault.com

投稿請附上社區文章地址

點擊左下角閱讀原文,到SegmentFault 思否社區和文章作者展開更多互動和交流,「公眾號後台「回復「入群」即可加入我們的技術交流群,收穫更多的技術文章~

-END -

arrow
arrow
    全站熱搜
    創作者介紹
    創作者 鑽石舞台 的頭像
    鑽石舞台

    鑽石舞台

    鑽石舞台 發表在 痞客邦 留言(0) 人氣()