react源碼總覽(翻譯)

用react也有段時間了, 是時候看看人家源碼了. 看源碼以前看到官方文檔 有這麼篇文章介紹其代碼結構了, 爲了看源碼能順利些, 遂決定將其翻譯來看看, 小弟英語也是半瓢水, 好多單詞得查詞典, 不當之處請批評. 直接從字面翻譯的, 後面看源碼後可能會在再修改下.javascript


下面是翻譯php

這部分將給你介紹下react代碼的基本結構, 代碼約定和它的基本實現.html

若是你想爲react貢獻代碼的話, 咱們但願這篇指南能讓你寫代碼更加舒服.java

咱們不推薦將這些約定用在react應用中, 由於這些約定大可能是基於一些歷史緣由存在的, 隨着時間推移可能會發生變化.node

外部依賴

react 幾乎沒有外部依賴. 一般require()指向的是react本身代碼庫的一個文件. 可是也有一些例外.react

因爲react想要經過庫共享一些諸如Relay的小工具, 因此存在fbjs repository, 並且咱們讓他們是同步的. 咱們沒有依賴任何node生態系統下的小模塊, 由於咱們但願facebook的工程師的能能再任何須要的時候修改他們. fbjs中的任何工具都不能被認爲是公共api, 而且他們只是爲Facebook的一些工程使用, 好比react.git

一級目錄

克隆了react的倉庫後你會發如今裏邊有幾個一級目錄.github

  • packages目錄包括一些元數據(如package.json)和react庫提供的全部包的源碼(src的下面), 若是你想修改代碼, src下面就是你要花時間最多的地方.算法

  • fixtures目錄包括了爲貢獻者準備的一些小的react的測試應用npm

  • 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 injection
  injection: {
    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

相關文章
相關標籤/搜索