一份 2.5k star 的《React 開發思想綱領》

大家好,我是若川。持續組織了6個月源碼共讀活動,感興趣的可以點此加我微信 ruochuan12?參與,每周大家一起學習200行左右的源碼,共同進步。同時極力推薦訂閱我寫的《學習源碼整體架構系列》?包含20余篇源碼文章。歷史面試系列

翻譯自:https://github.com/mithi/react-philosophies[1]?2.5k star
原文作者:mithi[2]
已獲作者授權

概要

  1. 介紹

  2. 最低要求

  3. 面向幸福設計

  4. 性能優化技巧

  5. 測試原則

🧘 0. 介紹

《React 開發思想綱領》是:

  • 我開發 React 時的一些思考

  • 每當我 review 他人或自己的代碼時自然而然會思考的東西

  • 僅僅作為參考和建議,并非嚴格的要求

  • 會隨著我的經驗不斷更新

  • 大多數技術點是基礎的重構方法論SOLID 原則以及極限編程等思想的變體,僅僅是在 React 中的實踐而已 🙂

你可能會覺得我寫的這些非常基礎。但以下示例都來自一些復雜大型項目的線上代碼。

《React 開發思想綱領》的靈感來源于我實際開發中遇到的各種場景。

🧘 1. 最低要求

1.1 計算機比你更「智能」

  1. 使用 ESLint 來靜態分析你的代碼,開啟 rule-of-hooksexhaustive-deps 這兩個規則來捕獲 React 錯誤。

  2. 開啟 JS 嚴格模式吧,都 2202 年了。

  3. 直面依賴,解決在useMemouseCallbackuseEffectexhaustive-deps 規則提示的 warning 或 error 問題。可以將最新的值掛在 ref 上來保證這些 hook 在回調中拿到的都是最新的值,同時避免不必要的重新渲染。

  4. 使用 map 批量渲染組件時,都加上 key

  5. 只在最頂層使用 hook,不要在循環、條件或嵌套語句中使用 hook。

  6. 理解不能對已經卸載的組件執行狀態更新的控制臺警告。

  7. 給不同層級的組件都添加錯誤邊界(Error Boundary)來防止白屏,還可以用它來向錯誤監控平臺(比如 Sentry)上報錯誤,并設置報警。

  8. 不要忽略了控制臺中打印的錯誤和警告。

  9. 記得要 tree-shaking!

  10. 使用 Prettier 來保證代碼的格式化一致性!

  11. 使用 TypescriptNextJS這樣的框架來提升開發體驗。

  12. 強烈推薦 Code Climate(或其他類似的)開源庫。這類工具會自動檢測代碼異味(Code Smell,代碼中的任何可能導致深層次問題的癥狀),它可以促使我去處理項目里留下的技術債。

1.2 Code is just a necessary evil

譯者注:程序員的目標是解決客戶的問題,代碼只是副產品

1.2.1 先思考,再加依賴

依賴加的越多,提供給瀏覽器的代碼就越多。捫心問問自己,你是否真的使用了某個庫的 feature?

🙈 ?你真的需要它嗎? 看看這些你可能不需要的依賴

  1. 你是否真的需要 Redux?有可能需要,但其實 React 本身也是一個狀態管理庫

  2. 你是否真的需要 Apollo clientApollo client 有許多很強大的功能,比如數據規范化。但使用的同時也會顯著提高包體積。如果你的項目使用的并非是 Apollo client 特有的 feature,可以考慮使用一些輕量的庫來替代,比如 react-querySWR(或者根本不用)。

  3. Axios 呢?Axios 是一個很棒的庫,它的一些特性不容易通過原生的 fetch API 來復刻。但是如果使用 Axios 只是因為它有更好的 API,完全可以考慮在 fetch 上做一層封裝(比如 redaxios 或自己實現)。取決于你的 App 是否真正地使用了 Axios 的核心 feature。

  4. Decimal.js 呢?或許 Big.js 或者其他輕量的庫就足夠了。

  5. Lodash/underscoreJS呢?推薦你看看【你不需要系列之“你不需要 Lodash/Underscore”】[3]

  6. MomentJS呢?【你不需要系列之“你不需要 Momentjs”】[4]

  7. 你不需要為了主題(淺色/深色模式)而使用 Context,考慮下用 css 變量 代替。

  8. 你甚至不需要 Javascript,CSS 也足夠強大。【你不需要系列之“你不需要 JavaScript”】[5]

1.2.2 不要自作聰明,提前設計

"我們的軟件在未來會如何迭代?可能會這樣或者那樣,如果在當下就開始往這些方向進行代碼設計,這就叫 future-proof(防過時,面向未來編程)。"

不要這樣搞! 應該在面臨需求的時候再去實現相應功能,而不是在你預見到可能需要的時候。代碼應該越少越好!

1.3 發現了就優化它

1.3.1 檢測代碼異味(Code Smell),并在必要時對其進行處理。

當你意識到某個地方出現了問題,那就馬上處理掉。但如果當前不容易修復,或者沒有時間,那請至少添加一條注釋(FIXME 或者 TODO),附上對該問題的簡要描述。來讓項目里的每個人都知道這里有問題,讓他們意識到當他們遇到這樣的情況時也該這樣做。

🙈 來看看這些容易發現的代碼異味

  • ? 定義了很多參數的函數或方法

  • ? 難以理解的,返回 Boolean 值的邏輯

  • ? 單個文件中代碼行數太多

  • ? 在語法上可能相同(但格式化可能不同)的重復代碼

  • ? 可能難以理解的函數或方法

  • ? 定義了大量函數或方法的類/組件

  • ? 單個函數或方法中的代碼行數太多

  • ? 具有大量返回語句的函數或方法

  • ? 不完全相同但代碼結構類似的重復代碼(比如變量名可能不同)

切記,代碼異味并不一定意味著代碼需要修改,它只是告訴你,你應該可以想出更好的方式來實現相同的功能。

1.3.2 無情的重構。簡單比復雜好。

💁?♀? 小技巧: 簡化復雜的條件語句,最好能提前 return。

🙈 提前 return 的示例

#???不太好if?(loading)?{return?<LoadingScreen?/>
}?else?if?(error)?{return?<ErrorScreen?/>
}?else?if?(data)?{return?<DataScreen?/>
}?else?{throw?new?Error('This?should?be?impossible')
}#???推薦if?(loading)?{return?<LoadingScreen?/>
}if?(error)?{return?<ErrorScreen?/>
}if?(data)?{return?<DataScreen?/>
}throw?new?Error('This?should?be?impossible')

💁?♀? 小技巧: 比起傳統的循環語句,鏈式的高階函數更優雅

如果沒有明顯的性能差異,盡量使用鏈式的高階函數(map, filter, find, findIndex, some等) 來代替傳統的循環語句。

1.4 你可以做的更好

💁?♀? 小技巧: 可以在 setState 時傳入回調函數,所以沒必要把 state 作為一個依賴項

你不用把 setStatedispatch 放在 useEffectuseCallback 這些 hook 的依賴數組中。ESLint 也不會給你提示,因為 React 已經確保了它們不會出錯。

#???不太好
const?decrement?=?useCallback(()?=>?setCount(count?-?1),?[setCount,?count])
const?decrement?=?useCallback(()?=>?setCount(count?-?1),?[count])#???推薦
const?decrement?=?useCallback(()?=>?setCount(count?=>?(count?-?1)),?[])

💁?♀? 小技巧: 如果你的 useMemouseCallback 沒有任何依賴,那你可能用錯了

#???不太好
const?MyComponent?=?()?=>?{const?functionToCall?=?useCallback(x:?string?=>?`Hello?${x}!`,[])const?iAmAConstant?=?useMemo(()?=>?{?return?{x:?5,?y:?2}?},?[])/*?接下來可能會用到?functionToCall?和?iAmAConstant?*/
}#???推薦
const?I_AM_A_CONSTANT?=??{?x:?5,?y:?2?}
const?functionToCall?=?(x:?string)?=>?`Hello?${x}!`
const?MyComponent?=?()?=>?{/*?接下來可能會用到?functionToCall?和?I_AM_A_CONSTANT?*/
}

💁?♀? 小技巧: 巧用 hook 封裝自定義的 context,會提升 API 可讀性

它不僅看起來更清晰,而且你只需要 import 一次,而不是兩次。

? 不太好

//?你每次需要?import?兩個變量
import?{?useContext?}?from?'react';
import?{?SomethingContext?}?from?'some-context-package';function?App()?{const?something?=?useContext(SomethingContext);?//?看起來?ok,但可以更好//?...
}

? 推薦

//?在另一個文件中,定義這個?hook
function?useSomething()?{const?context?=?useContext(SomethingContext);if?(context?===?undefined)?{throw?new?Error('useSomething?must?be?used?within?a?SomethingProvider');}return?context;
}//?你只需要?import?一次
import?{?useSomething?}?from?'some-context-package';function?App()?{const?something?=?useSomething();?//?看起來會更清晰//?...
}

💁?♀? 小技巧: 在寫組件之前,先思考該怎么用它

設計 API 很難,README 驅動開發(RDD)是個很有用的辦法,可以幫助你設計出更好的 API。并不是說應該無腦使用 RDD,但它背后的思想是很值得學習的。我自己發現,在設計實現組件 API 之前,使用 RDD 通常比不用時設計地更好。

🧘 2. 面向幸福設計

太長不看版

  1. 💖 通過刪除冗余的狀態來減少狀態管理的復雜性。

  2. 💖 “傳遞香蕉,而不是拿著香蕉的大猩猩和整個叢林“(意思是組件要什么傳什么,不要傳大對象)。

  3. 💖 讓你的組件小而簡單 —— 單一職責原則。

  4. 💖 復制比錯誤的抽象要“便宜”的多(避免提早/不恰當的設計)。

  5. 避免 prop 層層傳遞(又叫 prop 鉆取,prop drilling)。Context 不是解決狀態共享問題的銀彈。

  6. 將巨大的 useEffect 拆分成獨立的小 useEffect

  7. 將邏輯提取出來都放到 hook 和工具函數中。

  8. useCallback, useMemouseEffect 依賴數組中的依賴項最好都是基本類型。

  9. 不要在 useCallback, useMemouseEffect 中放入太多的依賴項。

  10. 為了簡單起見,如果你的狀態依賴其他狀態和上次的值,考慮使用 useReducer,而不是使用很多個 useState

  11. Context 不一定要放在整個 app 的全局。把 Context 放在組件樹中盡可能低的位置。同樣的道理,你的變量,注釋和狀態(和普通代碼)也應該放在靠近他們被使用的地方。

💖 2.1 刪除冗余的狀態來減少狀態管理的復雜性

冗余的狀態指可以通過其他狀態經過推導得到的狀態,不需要單獨維護(類似 Vue computed),當你有冗余的狀態時,一些狀態可能會丟失同步性,在面對復雜交互的場景時,你可能會忘記更新它們。

刪除這些冗余的狀態,除了避免同步錯誤外,這樣的代碼也更容易維護和推理,而且代碼更少。

💖 2.2 “傳遞香蕉,而不是拿著香蕉的大猩猩和整個叢林“

為了避免掉入這種坑,最好將基本類型(boolean, string, number 等)作為 props 傳遞。(傳遞基本類型也能更好的讓你使用 React.memo 進行優化)

組件應該僅僅只了解和它運作相關的內容就足夠了。應該盡可能地與其他組件產生協作,而不需要知道它們是什么或做什么。

這樣做的好處是,組件間的耦合會更松散,依賴程度會更低。低耦合更利于組件修改,替換和移除,而不會影響其他組件。

💖 2.3 讓你的組件小而簡單

什么是「單一職責原則」?

一個組件應該有且只有一個職責。應該盡可能的簡單且實用,只有完成其職責的責任。

具有各種職責的組件很難被復用。幾乎不可能只復用它的部分能力,很容易與其他代碼耦合在一起。那些抽離了邏輯的組件,改起來負擔不大而且復用性更強。

如何判斷一個組件是否符合單一職責?

可以試著用一句話來描述這個組件。如果它只負責一個職責,描述起來會很簡單。如果描述中出現了“和“或“或”,那么這個組件很大概率不是單一職責的。

檢查組件的 state,props 和 hooks,以及組件內部聲明的變量和方法(不應該太多)。問問自己:是否這些內容必須組合到一起這個歌組件才能工作?如果有些不需要,可以考慮把它們抽離到其他地方,或者把這個大組件拆解成小組件。

🧘 3. 性能優化技巧

  1. 如果你覺得應用速度慢,就應該做一次基準測試(benchmark)來證明。 "面對模凌兩可的情況,拒絕猜測。" 多使用 Chrome 插件 - React 開發者工具的 profiler!

  2. useMemo 主要用在大開銷的計算上。

  3. 如果你打算使用 React.memo, useMemo, 和 useCallback 來減少重新渲染,它們不該有過多的依賴項,且這些依賴項最好都是基本類型。

  4. 確保你清楚代碼里 React.memo, useCallbackuseMemo 它們都是為了什么而使用的(是否真的能防止重新渲染?是否能證明在這些場景中真的可以顯著提高性能? Memoization 有時會起到反作用,所以需要關注!)

  5. 優先修復慢渲染,再修復重新渲染。

  6. 把狀態盡可能地放在它被使用的地方,一方面讓代碼讀起來更順,另一方面,能讓你的 app 更快(state colocation(狀態托管))

  7. Context 應該按邏輯分開,不要在一個 provider 中管理多個 value。如果其中某個值變化了,所有使用該 context 的組件(即便沒有用到這個值),都會重新渲染。

  8. 可以通過拆分 statedispatch 來優化 context

  9. 了解下 lazy loading(懶加載)bundle/code splitting(代碼分割)

  10. 長列表請使用 tannerlinsley/react-virtual 或其它類似的庫。

  11. 包體積越小,app 越快。你可以使用 source-map-explorer 或者 @next/bundle-analyzer(用于 NextJS) 來進行包體積分析。

  12. 關于表單的庫,推薦使用 react-hook-forms,它在性能和開發體驗各方面都做的比較好。

🧘 4. 測試原則

  1. 測試應該始終與軟件的使用方式相似。

  2. 確保不是在測試一些邊界細節(用戶不會使用,看不到甚至感知不到的內容)。

  3. 如果你的測試不能讓你對自己的代碼產生信任,那測試就是無意義的。

  4. 如果你正在重構某個代碼,且最后實現的功能都是完全一致的,其實幾乎不需要修改測試,而且可以通過測試結果來判定你正確的重構了。

  5. 對于前端來說,不需要 100% 的測試覆蓋率,70% 就足夠了。測試應該提升你的開發效率,雖然維護測試會暫時地阻塞你目前的開發,但當你不斷地增加測試,會在不同階段得到不同的回報。

  6. 我個人喜歡使用 JestReact testing libraryCypress,和 Mock service worker

End

翻譯的不好,請大家見諒。如有任何想法,歡迎評論交流

參考資料

[1]

https://github.com/mithi/react-philosophies: https://github.com/mithi/react-philosophies

[2]

mithi: https://github.com/mithi

[3]

【你不需要系列之“你不需要 Lodash/Underscore”】: https://github.com/you-dont-need/You-Dont-Need-Lodash-Underscore

[4]

【你不需要系列之“你不需要 Momentjs”】: https://github.com/you-dont-need/You-Dont-Need-Momentjs

[5]

【你不需要系列之“你不需要 JavaScript”】: https://github.com/you-dont-need/You-Dont-Need-JavaScript

d31918a93a1031165c66986a39daf8ef.gif

·················?若川簡介?·················

你好,我是若川,畢業于江西高校。現在是一名前端開發“工程師”。寫有《學習源碼整體架構系列》20余篇,在知乎、掘金收獲超百萬閱讀。
從2014年起,每年都會寫一篇年度總結,已經堅持寫了8年,點擊查看年度總結。
同時,最近組織了源碼共讀活動,幫助3000+前端人學會看源碼。公眾號愿景:幫助5年內前端人走向前列。

7b6eb7654de883df2e88d8ace93b9dc9.png

掃碼加我微信 ruochuan02、拉你進源碼共讀

今日話題

略。分享、收藏、點贊、在看我的文章就是對我最大的支持~

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/274805.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/274805.shtml
英文地址,請注明出處:http://en.pswp.cn/news/274805.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

asp.net生成jason給js

[WebMethod(EnableSession true)][ScriptMethod]public static object TEST(string testval){int type 0;string message "";int precent 0;return new { type type, message message, precent precent };} 轉載于:https://www.cnblogs.com/bulege/archive/20…

文案寫作軟件_11種可改善網站用戶體驗的文案寫作技術

文案寫作軟件Written by John Stevens約翰史蒂文斯 ( John Stevens)撰寫 When we talk about user experience and your website, it is easy to get caught up in the site’s design and navigation options. While that is important, the words you place on the page are…

Table.Rows.Remove(dr)和Table.Delete()的區別

一個DataRow對象剛被創建之后其狀態是Detached&#xff0c;是孤立的一個存在&#xff0c;所以建立了DataRow之后在DataRow中的單元填充了數據后還要通過DataTable.Rows.Add(DataRow)方法將此DataRow添加到DataTable&#xff0c;DataRow添加到DataTable后, 這個DataRow的狀態就…

張小龍談用戶體驗

原文&#xff1a;http://sd.csdn.net/a/20120510/2805483.html從Foxmail到騰訊“七星級產品”QQ郵箱&#xff0c;再到騰訊核武器級產品微信。在外界看來&#xff0c;騰訊副總裁、廣州研發部總經理張小龍作風低調&#xff0c;很少接受正式的媒體采訪。然而作為當今國內最優秀的產…

如何高效學習前端新知識,我推薦這些~

眾所周知&#xff0c;關注公眾號可以了解學習掌握技術方向&#xff0c;學習優質好文&#xff0c;落實到自己項目中。還可以結交圈內好友&#xff0c;讓自己融入到積極上進的技術氛圍&#xff0c;促進自己的技術提升。話不多說&#xff0c;推薦這些優質前端公眾號前端之神100w閱…

web開發集成數字證書_每個數字設計師都應該知道的Web開發的七個原則

web開發集成數字證書A career path into digital design is often winding, meaning many practitioners come from adjacent fields as diverse as graphic design, web development, research, or even anthropology. As a result, two people working in a similar role may…

【轉】CentOS 6.6 升級GCC G++ (當前最新版本為v6.1.0) (完整)

原文地址&#xff1a;https://www.cnblogs.com/lzpong/p/5755678.html 我這里是centos7 升級到gcc8.1&#xff0c;過程差不多&#xff0c;參考這篇文章&#xff0c;記錄一下。 ---原文--- CentOS 6.6 升級GCC G (當前最新GCC/G版本為v6.1.0) 沒有便捷方式, yum update.... yu…

Hadoop:mapreduce的splitsize和blocksize

參考&#xff1a; Hadoop MapReduce中如何處理跨行Block和UnputSplit https://stackoverflow.com/questions/17727468/hadoop-input-split-size-vs-block-size https://stackoverflow.com/questions/30549261/split-size-vs-block-size-in-hadoop轉載于:https://www.cnblogs.co…

前端工程師生產環境 debugger 技巧

大家好&#xff0c;我是若川。持續組織了6個月源碼共讀活動&#xff0c;感興趣的可以點此加我微信 ruochuan12 參與&#xff0c;每周大家一起學習200行左右的源碼&#xff0c;共同進步。同時極力推薦訂閱我寫的《學習源碼整體架構系列》 包含20余篇源碼文章。歷史面試系列導言開…

bmp轉jpg(使用libjpeg)

jpg壓縮原理可以參考這篇文章http://hi.baidu.com/tiandsp/item/f5a2dcde6ef1405bd73aae41&#xff0c;我很早以前轉的一篇文章。 沒有使用libjpeg的壓縮代碼可以看看這篇文章http://hi.baidu.com/tiandsp/item/9b5843c58a3b4474cfd4f841&#xff0c;也是我很早以前轉的。 這次…

figma設計_Figma與Adobe XD:我們如何選擇下一個設計工具

figma設計The time came for changes and our design team started raising the topic again about how we should consider moving away from Sketch. This is not the first time this question came to mind, but this time seems like it was serious. Last summer we cons…

一個小廠前端 Leader 如何篩選候選人?

大家好&#xff0c;我是若川。持續組織了8個月源碼共讀活動&#xff0c;感興趣的可以點此加我微信 ruochuan12 參與&#xff0c;每周大家一起學習200行左右的源碼&#xff0c;共同進步。同時極力推薦訂閱我寫的《學習源碼整體架構系列》 包含20余篇源碼文章。歷史面試系列本文作…

figma設計_如何在Figma中構建設計入門套件(第1部分)

figma設計Figma教程 (Figma Tutorial) Do you like staring at a blank canvas every time you start a new project in Figma?每次在Figma中啟動新項目時&#xff0c;您是否喜歡盯著一塊空白的畫布&#xff1f; I’m guessing you’re not a big fan right, but it’s a pra…

純靠技術,很難進入大廠了。。。

日前&#xff0c;國務院印發《“十四五”時期就業促進規劃的通知》&#xff0c;其中明確指出&#xff0c;要完善終身學習體系&#xff0c;推進高水平大學開放教育資源&#xff0c;暢通在職人員繼續教育與終身學習通道。為響應國家政策&#xff0c;現臨時擴大招生規模&#xff0…

十天學會ASP.Net——(8)

1. ajax入門AJAX Extensions工具箱 &#xff08;1&#xff09;實現又刷新改變字體大小和無刷新改變字體大小 頁面設計&#xff1a; 前臺頁面設計&#xff1a; 首先需要在用到ajaxExtensions控件的位置之前放置一個ScriptManager控件&#xff0c;它將在瀏覽頁面時不可見&#xf…

聊聊 computed 影響性能的場景

大家好&#xff0c;我是若川。持續組織了8個月源碼共讀活動&#xff0c;感興趣的可以點此加我微信 ruochuan12 參與&#xff0c;每周大家一起學習200行左右的源碼&#xff0c;共同進步。同時極力推薦訂閱我寫的《學習源碼整體架構系列》 包含20余篇源碼文章。歷史面試系列前言在…

saej1929_(1929年-2020年)

saej1929Milton Glaser, the legendary graphic designer who co-founded New York Magazine, created the iconic ‘I ? NY’ logo, the psychedelic Bob Dylan poster, and the Brooklyn Brewery logo, passed away yesterday at the age of 91 on his birthday, June 26, 2…

Chap2-構造函數語意學

如果一個類沒有任何constructor&#xff0c;那么會有一個default constructor被隱式的聲明出來&#xff0c;一個implicit default constructor將是一個trivial&#xff08;無用的&#xff09;constructor。但是在某些情況下&#xff0c;implicit default constructor將是一個no…

【熱點】React18正式版發布,未來發展趨勢是?

大家好&#xff0c;我是若川。持續組織了8個月源碼共讀活動&#xff0c;感興趣的可以點此加我微信 ruochuan12 參與&#xff0c;每周大家一起學習200行左右的源碼&#xff0c;共同進步。同時極力推薦訂閱我寫的《學習源碼整體架構系列》 包含20余篇源碼文章。歷史面試系列2022年…

不要重新發明輪子_是否重新發明輪子

不要重新發明輪子Design is a profession that thrives on creativity. Us designers are constantly trying to innovate by thinking outside the box. We’ve seen design evolve across all sectors — print, digital, product, architecture etc. We have gone from type…