JavaScript >> Javascript 文檔 >  >> React

React 架構:如何構建和組織 React 應用程序

對於組織 React 應用程序的正確方法沒有達成共識。 React 給了你很大的自由,但隨著自由而來的是決定你自己的架構的責任。通常情況下,無論是誰在開始設置應用程序的人都會將幾乎所有內容都扔到 components 中 文件夾,或者可能是 componentscontainers 如果他們使用 Redux,但我建議有更好的方法。我喜歡仔細考慮如何組織我的應用程序,以便它們易於使用、理解和擴展。

我將向你展示我認為用於大規模生產 React 應用程序的直觀且可擴展的系統。我認為重要的主要概念是使架構專注於功能 而不是 type ,僅在全局級別組織共享組件,並在本地化視圖中將所有其他相關實體模塊化。

技術假設

由於本文將是固執己見,我將對項目將使用什麼技術做一些假設:

  • 應用程序 - 反應(鉤子)
  • 全局狀態管理 - Redux,Redux 工具包
  • 路由 - 反應路由器
  • 樣式 - 樣式化的組件
  • 測試 - Jest,React 測試庫

我對樣式沒有非常強烈的意見,無論是 Styled Components 還是 CSS 模塊或自定義 Sass 設置是否是理想的,但我認為 Styled Components 可能是保持樣式模塊化的最佳選擇之一。

我還將假設測試在代碼旁邊,而不是在頂級 tests 文件夾。這個我可以選擇任何一種方式,但是為了讓示例發揮作用,並且在現實世界中,需要做出決定。

如果您使用的是原版 Redux 而不是 Redux Toolkit,這裡的所有內容仍然適用。無論哪種方式,我都建議您將 Redux 設置為功能切片。

我對 Storybook 也很矛盾,但如果您選擇在項目中使用它,我會在這些文件中包含它的外觀。

為了示例,我將使用“圖書館應用程序”示例,它有一個用於列出書籍的頁面、一個用於列出作者的頁面,並具有一個身份驗證系統。

目錄結構

頂層目錄結構如下:

  • 資產 - 全局靜態資產,例如圖片、svg、公司徽標等。
  • 組件 - 全局共享/可重用組件,例如佈局(包裝器、導航)、表單組件、按鈕
  • 服務 - JavaScript 模塊
  • store - 全球 Redux 商店
  • utils - 實用程序、助手、常量等
  • 視圖 - 也可以稱為“頁面”,應用程序的大部分內容都將包含在此處

我喜歡盡可能保持熟悉的約定,所以 src 包含所有內容,index.js 是入口點,App.js 設置身份驗證和路由。

.
└── /src
    ├── /assets
    ├── /components
    ├── /services
    ├── /store
    ├── /utils
    ├── /views
    ├── index.js
    └── App.js

我可以看到您可能擁有的一些其他文件夾,例如 types 如果是 TypeScript 項目,middleware 如有必要,也許是 context 用於上下文等

別名

我會將系統設置為使用別名,因此 components 中的任何內容 文件夾可以導入為 @components , assets 作為 @assets 等。如果你有一個自定義的 Webpack,這是通過解析配置完成的。

module.exports = {
  resolve: {
    extensions: ['js', 'ts'],
    alias: {
      '@': path.resolve(__dirname, 'src'),
      '@assets': path.resolve(__dirname, 'src/assets'),
      '@components': path.resolve(__dirname, 'src/components'),
      // ...etc
    },
  },
}

它只是讓從項目中的任何地方導入並在不更改導入的情況下移動文件變得容易得多,而且你永遠不會得到像 ../../../../../components/ 這樣的東西 .

組件

components 內 文件夾,我會按類型分組 - forms , tables , buttons , layout 等。具體情況會因您的特定應用而異。

在此示例中,我假設您正在創建自己的表單系統,或者創建自己的與現有表單系統的綁定(例如,結合 Formik 和 Material UI)。在這種情況下,您將為每個組件創建一個文件夾 (TextField , Select , Radio , Dropdown 等),內部將是組件本身、樣式、測試和 Storybook(如果正在使用)的文件。

  • Component.js - 實際的 React 組件
  • Component.styles.js - 組件的樣式化組件文件
  • Component.test.js - 測試
  • Component.stories.js - 故事書文件

對我來說,這比擁有一個包含所有組件文件的文件夾、一個包含所有測試的文件夾和一個包含所有 Storybook 文件的文件夾等更有意義。所有相關的內容都組合在一起並且很容易找到.

.
└── /src
    └── /components
        ├── /forms
        │   ├── /TextField
        │   │   ├── TextField.js
        │   │   ├── TextField.styles.js
        │   │   ├── TextField.test.js
        │   │   └── TextField.stories.js
        │   ├── /Select
        │   │   ├── Select.js
        │   │   ├── Select.styles.js
        │   │   ├── Select.test.js
        │   │   └── Select.stories.js
        │   └── index.js
        ├── /routing
        │   └── /PrivateRoute
        │       ├── /PrivateRoute.js
        │       └── /PrivateRoute.test.js
        └── /layout
            └── /navigation
                └── /NavBar
                    ├── NavBar.js
                    ├── NavBar.styles.js
                    ├── NavBar.test.js
                    └── NavBar.stories.js

你會注意到有一個 index.js components/forms 中的文件 目錄。通常正確地建議避免使用 index.js 文件,因為它們不是明確的,但在這種情況下它是有道理的 - 它最終將成為所有表單的索引,看起來像這樣:

src/components/forms/index.js
import { TextField } from './TextField/TextField'
import { Select } from './Select/Select'
import { Radio } from './Radio/Radio'

export { TextField, Select, Radio }

然後,當您需要使用其中一個或多個組件時,您可以輕鬆地將它們一次全部導入。

import { TextField, Select, Radio } from '@components/forms'

我會推薦這種方法而不是製作 index.js 每個裡面 forms 中的文件夾 ,所以現在你只有一個 index.js 實際上索引整個目錄,而不是十個 index.js 文件只是為了使每個單獨文件的導入更容易。

服務

services 目錄不如 components 重要 ,但如果您正在製作應用程序其餘部分正在使用的純 JavaScript 模塊,它會很方便。一個常見的人為示例是 LocalStorage 模塊,它可能如下所示:

.
└── /src
    └── /services
        ├── /LocalStorage
        │   ├── LocalStorage.service.js
        │   └── LocalStorage.test.js
        └── index.js

服務示例:

src/services/LocalStorage/LocalStorage.service.js
export const LocalStorage = {
  get(key) {},
  set(key, value) {},
  remove(key) {},
  clear() {},
}
import { LocalStorage } from '@services'

LocalStorage.get('foo')

存儲

全局數據存儲將包含在 store 目錄 - 在本例中為 Redux。每個特性都有一個文件夾,其中包含 Redux Toolkit 切片以及操作和測試。此設置也可以與常規 Redux 一起使用,您只需創建一個 .reducers.js 文件和 .actions.js 文件而不是 slice .如果你使用 sagas,它可能是 .saga.js 而不是 .actions.js 用於 Redux Thunk 操作。

.
└── /src
    ├── /store
    │   ├── /authentication
    │   │   ├── /authentication.slice.js
    │   │   ├── /authentication.actions.js
    │   │   └── /authentication.test.js
    │   ├── /authors
    │   │   ├── /authors.slice.js
    │   │   ├── /authors.actions.js
    │   │   └── /authors.test.js
    │   └── /books
    │       ├── /books.slice.js
    │       ├── /books.actions.js
    │       └── /books.test.js
    ├── rootReducer.js
    └── index.js

您還可以添加類似 ui 的內容 商店的一部分,用於處理模式、toast、側邊欄切換和其他全局 UI 狀態,我發現這比擁有 const [isOpen, setIsOpen] = useState(false) 更好 到處都是。

rootReducer 您將導入所有切片並將它們與 combineReducers 組合 ,並在 index.js 您將配置商店。

實用程序

您的項目是否需要 utils 文件夾由您決定,但我認為通常有一些全局實用程序功能,如驗證和轉換,可以輕鬆地在應用程序的多個部分中使用。如果你保持井井有條 - 不僅僅是一個 helpers.js 包含數千個函數的文件 - 它可能對您的項目組織很有幫助。

.
└── src
    └── /utils
        ├── /constants
        │   └── countries.constants.js
        └── /helpers
            ├── validation.helpers.js
            ├── currency.helpers.js
            └── array.helpers.js

同樣,utils 文件夾可以包含您認為在全局級別上有意義的任何內容。如果您不喜歡“多層”文件名,則可以將其稱為 validation.js ,但在我看來,顯式並不會從項目中帶走任何東西,並且在您的 IDE 中搜索時更容易導航文件名。

查看次數

這是您應用的主要部分所在的位置:在 views 中 目錄。您應用中的任何頁面都是“視圖”。在這個小例子中,視圖與 Redux 存儲很好地對齊,但存儲和視圖不一定完全相同,這就是它們分開的原因。另外,books 可能來自 authors ,等等。

視圖中的任何內容都是可能僅在該特定視圖中使用的項目 - BookForm 只會在 /books 使用 路線和 AuthorBlurb 只會在 /authors 上使用 路線。它可能包括特定的表單、模式、按鈕、任何不是全局的組件。

將所有內容都集中在領域而不是將所有頁面放在 components/pages 中的優勢 是它可以很容易地查看應用程序的結構並知道有多少頂級視圖,並且知道僅由該視圖使用的所有內容在哪裡。如果有嵌套路由,可以隨時添加嵌套的 views 主路由中的文件夾。

.
└── /src
    └── /views
        ├── /Authors
        │   ├── /AuthorsPage
        │   │   ├── AuthorsPage.js
        │   │   └── AuthorsPage.test.js
        │   └── /AuthorBlurb
        │       ├── /AuthorBlurb.js
        │       └── /AuthorBlurb.test.js
        ├── /Books
        │   ├── /BooksPage
        │   │   ├── BooksPage.js
        │   │   └── BooksPage.test.js
        │   └── /BookForm
        │       ├── /BookForm.js
        │       └── /BookForm.test.js
        └── /Login
            ├── LoginPage
            │   ├── LoginPage.styles.js
            │   ├── LoginPage.js
            │   └── LoginPage.test.js
            └── LoginForm
                ├── LoginForm.js
                └── LoginForm.test.js

結論

這是我對 React 組織的系統的建議,該系統可以很好地擴展用於大型生產應用程序,並處理測試和样式以及以功能為中心的方式將所有內容放在一起。它比 components 中所有內容的傳統結構更嵌套 和 containers ,但由於 Redux 使用 Hooks 更容易實現,並且不再需要“智能”容器和“啞”組件,因此該系統有點過時了。

查看此系統並了解您的應用程序所需的一切以及在特定部分或全局影響應用程序的組件上去哪里工作很容易。這個系統可能不適用於每種類型的應用程序,但它對我有用。我很想听聽任何關於如何改進這個系統的意見,或者其他有優點的系統。


Tutorial JavaScript 教程
  1. 無服務器、容器或服務器方法。

  2. World Creator 2 - 構建世界地圖。

  3. 將嵌套對象轉換為數組 JavaScript |示例代碼

  4. [已解決] 未找到模塊:錯誤:無法解析 react-dom/client in

  5. var 和 let 的區別

  6. 需要節點——第 52 卷

  7. 使用 contextMenu.js 庫製作自定義上下文菜單

  1. 從頭開始構建網站。第 1 部分 - 描述和第一個設計

  2. JavaScript (ES5) 對象

  3. 面向前端開發人員的免費電子書和課程

  4. 所有關於花車

  5. 具有可變延遲和等待的 Angular 4 setTimeout()

  6. 另一個選項卡:使用 TypeScript 和 React 構建的開源 Chrome 擴展

  7. 如何為 GitHub 生成 SSH 密鑰

  1. Datetimepicker 下拉菜單未全尺寸顯示

  2. Javascript:變量和數據類型

  3. 自動化瀏覽器測試是現代 Web 開發的必要條件嗎?

  4. 開發者賓果