自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

偷師 Next.js:我學到的 6 個設計技巧

開發(fā) 前端
從 React 誕生之初一直到React Hooks推出并進化成完全形態(tài)。目前(2021/1/2)React Hooks 仍然不是完全形態(tài),componentDidCatch、getSnapshotBeforeUpdate、getDerivedStateFromError等特性還不健全,具體見Do Hooks cover all use cases for classes?

[[373397]]

本文轉載自微信公眾號「前端向后」,作者黯羽輕揚 。轉載本文請聯系前端向后公眾號。    

本文記錄了我從中發(fā)現的設計技巧,包括 API 設計、文檔設計、框架設計等,也分享給你

定義基類,可能不如定義模塊

首先,類(Class)和模塊(Module)都是組織代碼的可選方式,放到 API 設計的場景,都能用來約束寫法,暴露框架能力。而在模塊概念成為正統(tǒng)之前,前端框架大多提供基類來滿足這種需要,因為沒得選

典型的,React 通過React.Component基類暴露出各種生命周期 Hook,同時定義了組件寫法:

  1. // Components 
  2. class Clock extends React.Component { 
  3.   // Props 
  4.   constructor(props) { 
  5.     super(props); 
  6.     // State 
  7.     this.state = {date: new Date()}; 
  8.   } 
  9.  
  10.   // Lifecycle 
  11.   componentDidMount() { } 
  12.   componentWillUnmount() { } 
  13.  
  14.   render() { 
  15.     // Template 
  16.     return ( 
  17.       <div> 
  18.         <h1>Hello, world!</h1> 
  19.         <h2>It is {this.state.date.toLocaleTimeString()}.</h2> 
  20.       </div> 
  21.     ); 
  22.   } 

將 Props、State、Lifecycle、Template 等框架能力整合成一個 Class,稱之為組件。并且,在很長的一段時間里,React 中能稱為組件的只有 Class

這段很長的時間有多長?

從 React 誕生之初一直到React Hooks推出并進化成完全形態(tài)。目前(2021/1/2)React Hooks 仍然不是完全形態(tài),componentDidCatch、getSnapshotBeforeUpdate、getDerivedStateFromError等特性還不健全,具體見Do Hooks cover all use cases for classes?

也就是說,時至今日,React Components 仍等價于 Class Components,早期的函數式組件只能叫 Stateless Components,獲得 Hooks 加持之后的函數式組件雖然擺脫了 Stateless,但與完全形態(tài)的 Class Components 還有一點點差距

將 Components 概念與 Class 強綁定在一起真是個糟糕的選擇,被寄予厚望的 Hooks 充分說明了這一點。但 Props、State、Lifecycle、Template 這些框架能力又總要有東西來承載,那么,更好的選擇是什么呢?

可能是 Module。強調可能,是因為僅在組織代碼這一點上,Module 比 Class 更純粹。Module 只組織代碼,將變量、函數等語法元素圈在一起,而不像 Class 會強加實例狀態(tài)、成員方法等額外概念

例如,Next.js 的 Page 定義就只是個文件模塊:

  1. // pages/about.js 
  2. function About() { 
  3.   return <div>About</div> 
  4.  
  5. export default About 

最簡單的 Page,只要默認暴露出一個 React 組件即可。需要用到更多功能,再按需暴露更多的既定 API:

  1. // pages/blog.js 
  2. function Blog({ posts }) { 
  3.   // Render posts... 
  4.  
  5. // API 1 
  6. export async function getStaticProps() { } 
  7. // API 2 
  8. export async function getStaticPaths() { } 
  9. // API 3 
  10. export async function getServerSideProps() { } 
  11. // API n 
  12. export async function xxx() { } 
  13.  
  14. export default Blog 

對比 Class 形式的 API 設計,這種Module 式 API 設計更加純粹,不強加額外語法元素(尤其是 Class 這種根基龐大的語法元素,帶來一眾super()、bind(this)、static),在某些場景下不失為一種更好的選擇

文件約定路由

Next.js 里沒有Router.register、沒有new Route()、也沒有app.use(),沒有一切你能想到的路由定義 API

因為根本沒有 API,路由采用的是文件路徑約定:

  1. // 靜態(tài)路由 
  2. pages/index.js → / 
  3. pages/blog/index.js → /blog 
  4. pages/blog/first-post.js → /blog/first-post 
  5. pages/dashboard/settings/username.js → /dashboard/settings/username 
  6.  
  7. // 動態(tài)路由 
  8. pages/blog/[slug].js → /blog/:slug (/blog/hello-world) 
  9. pages/[username]/settings.js → /:username/settings (/foo/settings) 
  10. pages/post/[...all].js → /post/* (/post/2020/id/title) 

也就是說,通過源碼所在文件路徑來標識路由,甚至還能支持通配符,這么神奇,當然要親眼看看源碼目錄才能感受到視覺沖擊:

  1. pages 
  2. ├── _app.js 
  3. ├── _document.tsx 
  4. ├── api 
  5. │   ├── collection 
  6. │   │   ├── [id].tsx 
  7. │   │   └── index.tsx 
  8. │   ├── photo 
  9. │   │   ├── [id].tsx 
  10. │   │   ├── download 
  11. │   │   │   └── [id].tsx 
  12. │   │   └── index.tsx 
  13. │   ├── stats 
  14. │   │   └── index.tsx 
  15. │   └── user 
  16. │       └── index.tsx 
  17. ├── collection 
  18. │   └── [slug].tsx 
  19. └── index.tsx 

API 之間的無縫聯動

通過前兩篇文章,我們知道 Next.js 要解決的問題是預渲染,圍繞預渲染探索出了 SSG、SSR 兩種渲染模式,并在此基礎上支持了包括 CSR 在內的不同渲染模式混用:

  • ISR(Incremental Static Regeneration):增量靜態(tài)再生成,運行時定期重新生成靜態(tài) HTML
  • SSG 降級 SSR:未命中預先生成的靜態(tài) HTML 時,立即進行 SSR
  • SSR 帶靜態(tài)緩存:SSR 完成之后,將結果緩存起來,下次命中靜態(tài)緩存直接返回(相當于 SSG)
  • SSG 結合 CSR:編譯時生成靜態(tài)部分(頁面外框),CSR 填充動態(tài)部分(頁面內容)
  • SSR 聯動 CSR:URL 直接訪問走更快的 SSR,SPA 跳轉過來走體驗更優(yōu)的 CSR

從 API 設計的角度乍一看,似乎需要給每種組合取個別致的名字,并暴露出專門的 API,就像 SSGwithFallback、SSRwithStaticCache、PartialSSG、SPAMode…

然而,Next.js 不僅支持了所有這些混用特性,而且沒有增加任何頂層 API,它的做法是增加一些選項,例如:

  1. // SSG 基礎款 
  2. export async function getStaticProps(context) { 
  3.   return { 
  4.     props: {}, // will be passed to the page component as props 
  5.   } 
  6.  
  7. // SSG 變身 ISR,給返回值添上 revalidate 屬性 
  8. export async function getStaticProps(context) { 
  9.   return { 
  10.     props: {}, // will be passed to the page component as props 
  11.  
  12.     // Next.js will attempt to re-generate the page: 
  13.     // - When a request comes in 
  14.     // - At most once every second 
  15.     revalidate: 1, // In seconds 
  16.   } 
  17.  
  18. // SSG 感知路由的高級款,實現了 getStaticPaths 
  19. export async function getStaticPaths() { 
  20.   return { 
  21.     paths: [ 
  22.       { params: { ... } } // See the "paths" section below 
  23.     ], 
  24.     fallback: false 
  25.   }; 
  26.  
  27. // SSG 變身 SSR帶靜態(tài)緩存,fallback選項改為true 
  28. export async function getStaticPaths() { 
  29.   return { 
  30.     paths: [ 
  31.       { params: { ... } } // See the "paths" section below 
  32.     ], 
  33.     fallback: true 
  34.   }; 
  35.  
  36. // SSG 變身 SSG降級SSR,fallback選項改為'blocking' 
  37. export async function getStaticPaths() { 
  38.   return { 
  39.     paths: [ 
  40.       { params: { ... } } // See the "paths" section below 
  41.     ], 
  42.     fallback: 'blocking' 
  43.   }; 

這種基于細分選項的 API 聯動用起來更輕量,始終保持帶給用戶的漸進式體感,不需要一上來就了解全部 API、相關設計概念,從頂層區(qū)分我的場景屬于哪類,該用哪個 API,而是隨著場景的深入,發(fā)現那個最合適的 API/選項就在那里

能從文檔夠明顯地感受到這種差異,例如,Next.js 介紹 ISR 的地方將用戶指引到與之關聯的 SSR 帶靜態(tài)緩存模式:

Incremental Static Regeneration

With getStaticProps you don’t have to stop relying on dynamic content, as static content can also be dynamic. Incremental Static Regeneration allows you to update existing pages by re-rendering them in the background as traffic comes in.

This works perfectly with fallback: true. Because now you can have a list of posts that’s always up to date with the latest posts, and have a blog post page that generates blog posts on-demand, no matter how many posts you add or update.

積分、互動式新手教程

這一點算作文檔設計技巧(文檔,當然也要有設計),看過許多官方文檔/教程,留下深刻印象的只有 3 個:

  • Redux 文檔:故事性文檔,手把手一點點把 redux 設計出來,讀起來根本停不下來
  • Electron Demo App:交互式文檔,準確地說是帶完整文檔的 Demo,在體驗 Demo App 的同時了解相關特性用法,是比React 在做中學更偷懶的辦法了
  • Next.js 教程:積分、互動式新手教程,幾十頁的教程一口氣看完

P.S.Redux 文檔指的是2017 年的版本,現在貌似改過許多版,讀著很差勁了(這么點兒概念怎么能整出來那么多文檔)

積分、互動式新手教程威力大到什么程度?

讓我能在困到迷糊的狀態(tài)下堅持看完教程的全部內容,答對所有測試題目,積滿 500 分(當然,不用幻想,全對是沒有任何獎勵的),事后回想起來也覺得不可思議,其中的技巧在于:

  • 教程與文檔分離:導航欄一級菜單明確區(qū)分 Docs 與 Learn,教程中的部分概念有鏈到文檔,但不看完全也完全跟得上
  • 積分:教程醒目位置置頂展示獲得積分,每點一篇加分
  • 互動:關鍵章節(jié)有測試題,答對題目也加分,總積分可分享社交平臺(Twitter)

如此看來,在文檔中融入少量在線教育的成熟模式,可能效果極佳

默認提供最佳實踐

讀過體驗科技與好的產品,對其中玉伯提出的默認好用印象很深,而 Next.js 算是默認好用在框架設計上的一個真實案例

例如:

  • Link 自動預加載
  • Image 自動懶加載
  • “自動”采用最佳渲染模式:這個自動不同于前兩個,強調的是框架角度對用戶按需使用特性的回應,由框架來判斷渲染模式(該走 SSR 還是 SSG),而無需用戶顯式指定/切換

從生產活動的角度來看,最佳實踐本就應該是默認提供的,將新出現的最佳實踐不斷地下沉到環(huán)境層,就像 npm package、ES Module、Babel 等,如今的前端開發(fā)者已經幾乎不需要關心這些曾經的最佳實踐

僅從框架設計角度而言,默認好用要求在提供最佳實踐的基礎上更進一步,要把最佳實踐做沒,讓使用者能夠偷懶地以為一切本該如此。因此,最佳實踐只是一個臨時態(tài),尚未形成最佳實踐的部分才是開發(fā)者需要關心,并體現差異化競爭力的地方,一旦形成廣泛認同的最佳實踐,就應該沉淀成為默認的基礎設施,開發(fā)者無需關心即可獲得這些最佳實踐帶來的種種好處

從尚未形成最佳實踐,到提供最佳實踐,到默認提供最佳實踐,這 3 個階段可以通過一個圖片懶加載的示例來理解:

  1. // 第一階段:尚未形成最佳實踐 
  2. scroll 
  3. IntersectionObserver 
  4. // 業(yè)務各自實現,不存在用法示例 
  5.  
  6. // 第二階段:提供最佳實踐 
  7. React Lazy Load Component 
  8. // 用法示例 
  9. <LazyLoad height={683} offsetTop={200}> 
  10.   <img src='http://apod.nasa.gov/apod/image/1502/2015_02_20_conj_bourque1024.jpg' /> 
  11. </LazyLoad> 
  12.  
  13. // 第三階段:默認提供最佳實踐 
  14. next/image 
  15. // 用法示例 
  16. <Image 
  17.   src="/me.png" 
  18.   alt="Picture of the author" 
  19.   layout="fill" 
  20. /> 

第三階段與第二階段的區(qū)別在于,開發(fā)者不必關心哪個組件能夠提供懶加載功能(選擇最佳實踐),直接使用組件庫中最普通的 Image 組件,該有的功能自然就有,而懶加載只是其中一項

向 Serverless 延伸

Serverless 浪潮之下,前端生態(tài)也正在發(fā)生著一些變化,涌現出各式各樣的一體化應用:

  • 以前端項目/后端項目為主體的一體化應用:如 Midway Serverless,支持集成 React、Vue 等前端項目
  • 以 SSR 為主體的一體化應用:如 Next.js,支持將 SSR 和數據接口(API endpoints)部署成 Serverless Functions

Next.js 提供 SSR 支持,本就需要服務端環(huán)境,Serverless 的興起很好地解決了 SSR 渲染服務的運維問題,因此,其 Vercel 平臺默認支持以 Serverless Functions 的形式部署 SSR 服務與 API:

Pages that use Server-Side Rendering and API routes will automatically become isolated Serverless Functions. This allows page rendering and API requests to scale infinitely.

諸如此類的一體化應用雖未形成最佳實踐,但傳統(tǒng)的前端框架正在歷經變革。也許,在未來的某一天,取而代之的是與 Serverless 技術充分融合的一體化應用框架,Universal 體系大行其道也未可知。

原文鏈接:https://mp.weixin.qq.com/s/F_4yg-0hsX0PSQ1oEOopZg

 

責任編輯:武曉燕 來源: 前端向后
相關推薦

2024-09-20 15:37:02

2025-03-31 00:00:02

2024-09-18 15:58:05

2013-06-25 11:06:51

編程技巧蘋果

2025-04-08 08:12:26

Next.js組件ChatGPT

2024-12-13 08:37:32

2024-04-01 07:58:49

Next.js 14ReactWeb應用

2025-02-03 00:00:35

2024-07-31 08:38:36

2025-01-17 09:29:42

2024-11-25 07:39:48

2024-05-09 09:01:03

2011-07-11 10:34:40

編程技巧蘋果

2024-04-28 10:56:34

Next.jsWeb應用搜索引擎優(yōu)化

2024-09-04 10:27:53

2024-03-29 08:32:01

Node.jsNext.js組件

2020-12-14 11:40:27

Next.js SSRReact

2024-12-16 08:40:51

2025-03-06 00:00:00

2024-02-05 11:55:41

Next.js開發(fā)URL
點贊
收藏

51CTO技術棧公眾號