這篇文章接下來會讓優化從開資料夾開始,從優化專案結構的三種設計模式切入
- Model View Controller Pattern (MVC)
- Model-View-ViewModel Pattern (MVVM)
- Flux Pattern
Design Patterns 依照目的分成三群:
- Creational Patterns 創建型
- Structural Patterns 結構型,結構型設計模式根據實際情況會分成三種:
- Behavioural Patterns 行為型
Model View Controller Pattern (MVC)
Model View Controller (MVC) 模式是一種用於管理程式的結構和邏輯,提供定義清晰的架構,開發上能夠更容易地理解、擴展和測試,架構主要分為三個部分:
- Model: 處理數據的讀取、寫入和驗證等業務邏輯操作
- View: 處理數據的顯示和呈現以及用戶互動,可以是 HTML 樣板、頁面元素
- Controller: 接收來自界面的輸入和事件,並根據這些輸入和事件來更新模型和 UI
MVC 是將應用程式的邏輯、數據和界面分離,達到結構化和可重用性。
- 第一種是依照資料表去做區分,把同個資料表的 model、controller、route 集中存放,覺得較適合大型專案。
├── src/
│ ├── entities/ # 按照資料表去區分
│ │ └── user/ # 使用者表
│ │ ├── model.js # Schema 定義
│ │ ├── controller.js # 資料庫 CRUD
│ │ └── route.js # API 設定
│ └── index.js # 入口
├── .eslintrc # ESLint 設定檔
├── package-lock.json
├── package.json
└── README.md
- 第二種則是依照功能性,controller、routes、models 集中放置在各自的分類資料夾,覺得較適合小型專案。
├── src/
│ ├── controller/ # 資料庫 CRUD
│ ├── routes/ # API 設定
│ ├── models/ # Schema 定義
│ └── index.js # 程式入口
├── .eslintrc # ESLint 設定檔
├── package-lock.json
├── package.json
└── README.md
Model-View-ViewModel Pattern (MVVM)
Model-View-ViewModel Pattern (MVVM) 著重在開發的關注點分離並提供單向或是雙向的 Data Binding 來控制 UI 的顯示邏輯。
- Model: 定義資料結構,執行資料操作,在 React 中通常是元件中或是 Store 裡的狀態
- View (stateless): UI 介面,根據 ViewModel 來顯示,實際上的 HTML element 由 JSX 背後的 virtual dom 所控制
- ViewModel (stateful): 處理 Model 和 View 之間的溝通,用來維護 UI 的狀態,在 React 中的 JSX 就是扮演這個腳色
一個常見的 MVVM 資料流:
- ViewModel 從 Model 擷取資料並準備在 View 顯示
- View 把和 ViewModel binding 的資料顯示在 UI 中
- 透過 View 觸發命令或輸入事件
- ViewModel 監控互動並執行資料操作並更新 Model
- 如果 Model 資料變更,ViewModel 會通知視圖讓 UI 重新渲染
Flux Pattern
Flux pattern 是由 Facebook 提出將狀態中央化管理的機制,定義了單向資料流的架構明確將程式分為四個核心概念:
- Actions: 描述事件,例如使用者操作或 API 請求完成,由 type 和 payload 組成
- Dispatcher: 提供中央管理的機制,用於接收和發送 Actions,當事件發生時,Actions 會被集中到 Dispatcher 並操作對應的 Store
- Stores: 負責存儲和管理應用程式的狀態,只接受 Dispatcher 過來的 Actions,並根據 Action Type 來更新狀態
- Views: UI 訂閱 Store 的變化,並依據狀態來更新。當用戶進行操作時,UI 會產生 Action 並送到 Dispatcher 中去跟 Store 互動
搭配 Redux 後,主要就是增加元件之間需要溝通工具,會有以下特性:
- 單向資料流
- 公共的狀態儲存 (Store)
專案架構也會受到這種概念去分類:
- actions: 觸發狀態改變用的 function
- pages: 頁面容器元件
- containers: 有連接 Store
- components: 沒有連接 Store
- reducers: 收到 action 後的資料邏輯
所以專案資料夾架構依照屬性去分類就會長成下面這個樣子,在完成任務的過程中需要在多個不同的資料夾中來回,覺得較適合小型專案。
└── src
├── actions
│ ├── typeOneActions.js
│ └── typeTwoActions.js
├── api
│ ├── apiHandler.js
│ ├── typeOneApi.js
│ └── typeTwoApi.js
├── components
│ ├── TypeOneComponent.jsx
│ ├── TypeOneListComponent.jsx
│ ├── TypeTwoComponent.jsx
│ ├── TypeTwoPageComponent.jsx
│ └── HomePageComponent.jsx
├── containers
│ ├── TypeOneContainer.js
│ └── TypeTwoPageContainer.js
├── pages
│ └── HomePageContainer.js
├── index.js
├── reducers
│ ├── typeOneReducer.js
│ └── typeTwoReducer.js
├── routes.js
├── store.js
└── utils
以之前弄的小專案當例子,如果有加上 redux 的話,專案架構大概會長成下面的樣子,在比較簡單的專案中可以更簡化。
├── .storybook
├── src/
│ ├── constants/
│ ├── utils/
│ ├── pages/
│ ├── containers/ # containers 放置與 Redux 連接的相關元件,單元測試檔案為 `元件名稱.test.js`
│ ├── components/ # components 放置相關元件,單元測試檔案為 `元件名稱.test.js`
│ │ └── Root.js # 路由根目錄
│ ├── hooks/ # hooks 相關
│ ├── middleware/ # 資料處理相關
│ │ ├── API.js # axios 的 instance
│ │ └── redux-api.js # redux-api
│ ├── styles/ # 樣式檔們
│ ├── index.js # 程式入口
│ ├── serviceWorker.js
│ └── setupTests.js # 測試相關設定
├── .eslintrc # ESLint 設定檔
├── .prettierrc # prettierrc 工具設定
├── .travis.yml # 持續發佈工具
├── package-lock.json
├── package.json
└── README.md
在使用 Redux 的時候,我們通常要同時維護 reducer 以及 action,如果還要搭配 API 進行,又會需要多維護一個 middleware。
可是在簡單的專案中,絕大多數時候我們進行的工作都是類似的,官方也有相關的建議,甚至後來還推出了 toolkit 來協助寫法簡化。
簡單來說,本來要維護三個地方,現在變成只要維護一份配置檔就好了。
src
└── features
├── typeOne
│ ├── TypeOne.js
│ ├── TypeOne.styles.scss
│ └── typeOneSlice.js
├── typeTwo
│ ├── TypeTwo.js
│ ├── TypeTwo.styles.scss
│ └── typeTwoSlice.js
└── typeThree
├── TypeThree.js
├── TypeThree.styles.scss
└── typeThreeSlice.js
喜歡這篇文章,請幫忙拍拍手喔 🤣