react源码总览(翻译)
用react也有段時間了, 是時候看看人家源碼了. 看源碼之前看到官方文檔 有這么篇文章介紹其代碼結構了, 為了看源碼能順利些, 遂決定將其翻譯來看看, 小弟英語也是半瓢水, 好多單詞得查詞典, 不當之處請批評. 直接從字面翻譯的, 后面看源碼后可能會在再修改下.
下面是翻譯
這部分將給你介紹下react代碼的基本結構, 代碼約定和它的基本實現.
如果你想為react貢獻代碼的話, 我們希望這篇指南能讓你寫代碼更加舒服.
我們不推薦將這些約定用在react應用中, 因為這些約定大多是基于一些歷史原因存在的, 隨著時間推移可能會發生變化.
外部依賴
react 幾乎沒有外部依賴. 通常require()指向的是react自己代碼庫的一個文件. 但是也有一些例外.
由于react想要通過庫共享一些諸如Relay的小工具, 所以存在fbjs repository, 而且我們讓他們是同步的. 我們沒有依賴任何node生態系統下的小模塊, 因為我們希望facebook的工程師的能能再任何必要的時候修改他們. fbjs中的任何工具都不能被認為是公共api, 并且他們只是為Facebook的一些工程使用, 比如react.
一級目錄
克隆了react的倉庫后你會發現在里邊有幾個一級目錄.
packages目錄包括一些元數據(如package.json)和react庫提供的所有包的源碼(src的下面), 如果你想修改代碼, src下面就是你要花時間最多的地方.
fixtures目錄包括了為貢獻者準備的一些小的react的測試應用
build是react打包輸出的目錄. 他不在代碼庫管理范疇, 但是當你第一次打包后就會生成.
文檔是放在和react不同的另一個倉庫管理的.
還有一些其他一級目錄, 他們大多是工具層面的, 在你貢獻代碼時可能不會用到他們能.
共同測試(Colocated Tests)
我們沒有搞個一級目錄來做單元測試. 我們把它放在了被測試文件相鄰的被稱為__tests__的目錄.
舉個例子, 對于setInnerHTML.js這個文件的測試被放在與他同級的__tests__/setInnerHTML-test.js這個里邊.
這個詞不知道怎么翻譯
Warnings and Invariants
react中使用warning模塊顯示警告信息.
var warning = require('warning');warning(2 + 2 === 4,'Math is not working today.' );當警告條件是false的時候會展示警告信息
可以這么理解, 條件應該指示正常的情況, 而不是異常的情況. 就是說第一個參數是true表示的是正常, false是異常.
最好避免使用console取代warnings.
var warning = require('warning');var didWarnAboutMath = false; if (!didWarnAboutMath) {warning(2 + 2 === 4,'Math is not working today.');didWarnAboutMath = true; }警告只會在開發模式被開啟. 生產環境下被去掉了. 如果你想阻止某些代碼塊的執行, 那么你可以用invariant模塊.
var invariant = require('invariant');invariant(2 + 2 === 4,'You shall not pass!' );當條件為false時, 這個方法會直接拋出異常.
“Invariant” 就是說這個條件為真, 你可以認為他就是做了個斷言.
保持開發環境和生產環境一致是很重要的, 因此invariant在生產環境和開發環境都可以拋出異常. 生產環境下的錯誤消息被自動替換成錯誤碼, 以防增加代碼體積.
Development and Production
你可以使用__DEV__這個為全局變量指定僅僅在開發環境才執行的代碼塊.
他是在編譯過程中工作的, 他是在commonjs編譯的時候檢查process.env.NODE_ENV !== 'production'這個值.
單獨編譯的時候, 他在未壓縮版是true, 在壓縮版直接被去掉了.
if (__DEV__) {// 這里邊的代碼只會帶開發環境執行 }Flow
我們最近開始引入flow做靜態類型檢查, 在文件頭的注釋里標注了@flow的使用了類型檢查.
我們接受在現有代碼加入flow類型檢查的pull request (不錯哎, 可以試著提個pull request哦). Flow的簽名類似下面這樣.
ReactRef.detachRefs = function(instance: ReactInstance,element: ReactElement | string | number | null | false, ): void {// ... }時機成熟的時候, 新代碼要用Flow 簽名, 你可以在本地運行yarn flow用Flow檢查你的代碼.
動態植入
react在一些模塊使用了動態植入. 但是這個東西不太好, 因為他讓代碼比較難理解了. 他存在的理由是react一開始只把支持dom作為目標的. 但是后來殺出了個React Native, 他是基于react的, 我們不得不加入動態植入好讓react native 重載一些行為.
你可能會看到模塊像下面這樣聲明它的動態依賴
// Dynamically injected var textComponentClass = null;// Relies on dynamically injected value function createInstanceForText(text) {return new textComponentClass(text); }var ReactHostComponent = {createInstanceForText,// Provides an opportunity for dynamic injectioninjection: {injectTextComponentClass: function(componentClass) {textComponentClass = componentClass;},}, };module.exports = ReactHostComponent;注入的部分沒有以任何方式特殊處理. 但是規定, 它的意思是這個模塊想在運行時有一些依賴(可能是平臺特定的)被注入進去.
代碼里邊有幾個注入的入口. 未來, 我們將廢棄掉這種動態植入的機制, 方案是在編譯時以靜態方式處理他們.
多包
react是個monorepo, 他的倉庫包含了多個獨立的包, 因此他們的修改可以合在一起, 而且issues也可以放在一個地方.
React核心
react的核心是所有頂級api, 包括:
- React.createElement()
- React.Component
- React.Children
react核心只包括定義組件必要的api, 并不包括reconciliation算法和平臺特定代碼. React DOM和React Native都使用了他們.
react核心的相關代碼在packages/react里邊. npm使用時在react這個包里邊, 瀏覽器版的是react.js, 他掛載一個被稱為React的全局變量.
Renderers
react起初是為DOM創造的, 但是后臺通過RN被用來支持原生環境了. 這里介紹加react內部的“renderers”的理念.
“renderers”管理了react樹如何變成平臺可調用的東西.
Renderers也在packages里邊
React DOM Renderer 把react 組件渲染進 DOM. 他實現了頂級的ReactDOM APIs, 在react-dom這個npm包里被暴露出來. 瀏覽器版叫react-dom.js, 通過ReactDOM這個全局變量暴露出來.
React Native Renderer把react組件渲染到原生視圖層里. 他被RN內部使用.
React Test Renderer 把react組件渲染成JSON樹, 他被Jest的一個特性Snapshot Testing使用, 在react-test-renderer這個npm包里可用.
另一個官方唯一支持的渲染器是react-art, 他曾經是個獨立的庫, 現在被移進來了.
注意
技術上react-native-renderer是很薄的一層, 只是用來和RN的實現相互配合, 真正的平臺相關代碼是RN庫里一些native view.
Reconcilers(協調器)
相當多的渲染器, 如Reat DOM, React Native 需要共享一套邏輯. 尤其reconciliation算法需要足夠的相似, 以便讓rendering, 自定義組件, 狀態, 生命周期函數和refs能跨平臺工作.
為了解決這個問題, 不同的渲染器共用一些代碼. 我們把React 中的這個部分叫做"reconciler". 當一個更新比如setState要執行了,Reconcilers就去在組件上調用render(), 然后mounts, updates, 或者unmounts他們.
Reconcilers沒有獨立成包, 因為他現在還沒有公共API. 相反, 他僅僅是在渲染器被使用, 比如React DOM , React Native.
Stack Reconciler
Stack Reconciler 是在react15之前實現使用的, 現在已經不用了, 但是下一部分的文檔還會有詳細的介紹.
Fiber Reconciler
"Fiber"是為了解決stack reconciler固有問題和修復長期存在的bug所做的努力, 他從react16開始成為默認的Reconciler.
他的主要目標是:
在chunks里分離可中斷的工作
在過程中重建, 重用work或者改變他的優先級(瞎翻譯的)的能力
在父子組件前進或回退以只是react中的布局的能力
在render方法里返回多個元素的能力
更好的支持錯誤邊際
你可在這里和這里關于Fiber架構的相關信息. 但是React16對他做了封裝, 默認不支持異步特性了.
他的源碼在packages/react-reconciler里邊.
事件系統
react實現了一個對renders透明的事件系統, 這個系統被用于react dom 和react native. 源碼在packages/events;
這里有個視頻https://www.youtube.com/watch?v=dRo_egw7tBc
轉載于:https://www.cnblogs.com/floor/p/10094323.html
《新程序員》:云原生和全面數字化實踐50位技術專家共同創作,文字、視頻、音頻交互閱讀總結
以上是生活随笔為你收集整理的react源码总览(翻译)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 十五周 苏浪浪 201771010120
- 下一篇: 自动化测试前序(https://blog