掌握NextJS架構與TypeScript思維 | 2024年設計抽象
Next.js 是一個強大的用于構建React應用的框架,當與TypeScript結合使用時,它提供了強大的類型檢查和工具,可以顯著提升我們的開發體驗。
多年來我一直在使用 Next.JS,在開發大型可擴展web應用時,我發現它是一個出色的工具,甚至比Create React App 還要好。
在過去幾年里,NextJS 不斷發展,同時保持了其內部的可擴展抽象。在構建眾多應用時,我發現最有價值的是如何正確地抽象你的代碼。
找到一個關于構建精通的"Hello World"應用的手冊并不是特別困難。盡管它們可能解釋得很好,但這類故事中最大的瓶頸是當你需要開始處理真實世界的事物時。
一旦你被要求構建一個帶有身份驗證、多個API、服務和數據結構的NextJS應用,它與"Hello World"完全不同。
在本文中,我們將介紹如何使用 TypeScript 設置 Next.js 項目,處理導航,管理注冊/登錄/登出,以及有效地使用SVG資產,這些都將以你編寫真實的、生產就緒的應用的方式進行描述。
先決條件
在本文中,我們將嘗試復制一個全棧社交閱讀俱樂部應用。雖然我們不會涉及任何后端內容,但我們將使用瀏覽器的 LocalStorage 和 SessionStorage 來假裝我們在使用瀏覽器。
因此,一旦你需要攜帶后端,你將能夠輕松地切換到nodeJS + MongoDB/PostgressDB。無論如何,讓我們開始吧。
讓我們想象一下,你被要求:
- 創建必要的頁面:/,/feed,/signup,/signin,/signout,/:username,/friends。
- 創建導航菜單,考慮響應式設計。
- 集成用戶認證/登出流程,以便我們不會暴露內部社交數據。
- 添加CRUD操作以管理用戶帖子和好友列表。
- 用基本的顏色主題和整體樣式來設計應用;
聽起來相當簡單?確實如此。我們不需要使用過于復雜的例子來真正觸及架構設計。上述需求集是你在真實世界的應用中需要覆蓋的內容,所以我們嘗試掌握它。
使用TypeScript設置Next.js項目
首先,我們使用TypeScript初始化一個新的 Next.js 項目。打開你的終端并運行以下命令來創建一個新的Next.js項目并進入項目目錄:
npx create-next-app@latest my-nextjs-app --typescript
cd my-nextjs-app
通過這個,我們將初始化NextJS框架并在其中添加typescript。它將創建一個Starter Kit環境來開發我們未來的應用。
在 package.json 或 tsconfig.json 文件方面沒有什么特別有趣的內容需要覆蓋,因為它們是開箱即用的,你可以在網上找到關于它們如何工作的必要信息,所以讓我們假設你已經知道它們是如何工作的。
我們開始架構設計。
設計應用架構
所以這個故事的第一步是從選擇正確的文件夾結構開始。
雖然一些文件夾(如/pages)默認已定義,但我們需要自己設計其余的必要項。但是,我們先討論pages。
?? ./app
這是NextJS的核心文件夾,在大多數情況下,它可以保持盡可能簡單。大多數時候,這是你想設置核心邏輯的地方。
圖片
- favicon.ico — 用于瀏覽器標簽視覺設計的.ico文件。
- layout.tsx — 一個內部NextJS應用,將作為SSR或SSG渲染的入口點,但這不是我們的情況,因為我們現在的目標是CSR。
?? ./pages
默認情況下,NextJS為我們提供了一個漂亮的頁面開發抽象。你需要做的只是用必要的內容填充文件夾。
所以這是我們的設計:
圖片
_app.tsx — 是NextJS項目的主要入口點。它將擁抱整個應用,以便在運行時可以服務。feed/friends/home/signin/signout/signup.tsx — 是靜態頁面,將代表需要在屏幕上顯示的頁面,沒有任何動態行為。
[username].tsx — 是我所說的"動態行為"。一旦你有一個或多或少復雜的應用邏輯,你會想要通過相同的靜態頁面顯示動態內容,但考慮到一些用戶的ID或其他動態值。
?? ./components
這里我們可以存儲我們應用的每個可重用組件。這是最適合那些可以在應用的幾個區域/頁面中使用的東西的地方。
圖片
AddPostModal.tsx — 我們稍后將在我們的應用中使用它,允許我們的用戶按需添加新帖子。
Header.tsx — 我們可重用的頭部,將在web應用設計中扮演關鍵角色。
NavBar.tsx — 另一個可重用的組件,將代表應用的導航。
?? ./auth
這個文件夾將擁抱應用的核心邏輯,這將幫助我們識別我們的用戶是否登錄。
圖片
AuthContext.tsx — 用戶的認證信息將存在的地方。我們將使用React Context來管理用戶登錄系統后的靜態數據。
withAuth.tsx — 是一個HOC函數,將幫助在應用中共享用戶數據。
?? ./api
在處理應用的不同層(表現/業務等)時,始終重要的是不要將它們混在一起。
此外,將你的API相關代碼移到它自己的文件夾是一個好的做法。
圖片
- **getCurrentUser.ts **— 從SessionStorage檢索登錄用戶數據的GET請求。
- getPosts.ts — 檢索用戶發布的可用帖子的GET請求。
- **getUsers.ts **— 檢索系統中所有注冊用戶的GET請求。
- setCurrentUser.ts — 用戶成功登錄/注冊后設置用戶數據的POST請求。
- setUsers/setPosts.ts — 用于填充LocalStorage以初始化應用的POST請求。
?? ./hooks
在React的世界中(特別是說到hooks時),最佳實踐始終是不要將UI邏輯與業務邏輯混在一起。在設計你的組件時,總是想辦法保持你的UI層盡可能的傻瓜化。
在這種情況下,我們可以將任何異步請求切分下來,將它們放入它們自己的封裝作用域中,這樣UI組件將保持小巧和清潔。
圖片
- useDataInitialize.ts — 我們的主要工具,用于初始化應用運行的一組模擬數據。
- usePosts/useFriends.ts— 這些hooks將使我們有機會以封裝的方式檢索朋友/帖子API響應。
- useSignup/useSignin/useSignout.ts — 將幫助我們功能性地管理用戶認證流程。
?? ./helpers
這是一個小工具,可以為任何類型的操作服務于我們的自定義需求。在這個文件夾中,總是好放一些只用于特定用例的東西,比如數據隨機化等。
圖片
- dataRandomizer.ts — 這是我們的主要helper,用隨機帖子/用戶數據填充應用。
?? ./utils
這是一個相當標準的文件夾,將通過組合可以在整個應用中多次有用和可重用的東西來幫助提高應用的可重用性。
圖片
- sortByDate.ts — 幫助按特定時間戳對數據數組進行排序。
?? ./interfaces
在談到TypeScript時,你將需要處理類型和接口。在大多數Hello World應用的情況下,它們應該足夠小,可以自然地保留在代碼中。
然而,在真實世界的應用中,你可能會將它們分開,這樣行數會比包含它們時顯著減少。
圖片
- **data.ts **— 我們的數據結構接口,目前只有一個,當然將來會有更多。
?? ./static
這個小文件夾將代表你想包含在應用中的任何類型的靜態數據,如圖標/圖片/gif/視頻等。
圖片
- logo.svg — 主應用logo。
?? ./styles
最后但并非最不重要的是我們熟知的樣式文件夾。我鼓勵你使用CSS Modules,這樣你的代碼將保持隔離和不重復。盡管如此,一些代碼應該保持集中并在整個站點范圍內初始化。這就是存儲這些東西的地方,比如globals等。
圖片
- global.css — 應用的核心可共享樣式。
核心架構原則
好的,所以我們在設計應用架構方面做得很好,現在我們可以專注于其他重要的事情,如代碼的可重用性和可維護性。
更少的耦合,更多的內聚
圖片
內聚指的是模塊/類的元素屬于一起的程度,建議相關的代碼應該盡可能靠近,所以我們應該爭取高內聚,并將所有相關的代碼盡可能緊密地綁定在一起。這與模塊/類內的元素有關。
耦合指的是不同模塊/類之間相互依賴的程度,建議所有模塊應盡可能獨立,這就是為什么要低耦合。這與不同模塊/類之間的元素有關。
將業務邏輯從表示層中分離
很多時候,我看到人們試圖在UI組件的范圍內混合所有東西。無論是單個還是幾個被切分下來,瓶頸仍然是無論你想更新UI還是業務邏輯,你都需要同時處理兩者。
只要組件一次包含多于1個事物,你就需要檢查/審查/測試每一個。
React帶給我們的一個更好的方法來簡化代碼可維護性是Hooks。當考慮代表組件調用一些API請求時,問問自己是否最好將這段代碼拿出來放到不同的文件夾/范圍并將其作為隔離的管理?
在那種情況下,我們將有一個看起來更好的UI層:
圖片
...以及業務層:
圖片
現在,注意這里你處理的是API調用 — getUsers()。想象一下,如果你把它的邏輯直接放在這里...呃,在一個地方維護所有這些會有點混亂。
這就是為什么我們之前設計了一個專門的API文件夾來保存我們的核心API邏輯:
圖片
最后是接口...這里你可以看到我們將它們從代碼中移出到我們可共享的./interfaces文件夾,這使得API代碼現在更加清晰、易于理解和可擴展。
這是編寫干凈和高效代碼的4步最佳實踐,一旦你為你的NextJS項目設計了精心設計的抽象。我希望現在你更明白為什么我們需要按照上面討論的架構進行。
總結
仍然有許多事情需要涵蓋,因為設計應用架構不是一天就能完成的任務。一些公司花費數月時間僅僅討論可能的架構方式,然后才開始設計應用架構。
然而,我希望這個小小的真實世界例子能教會你如何更好地設計你未來的應用,并在開發web應用時給你一種正確抽象的感覺。