[譯]React16帶來了什麼以及對Fiber的解釋

玄學醬發表於2017-10-16
本文講的是[譯] React 16 帶來了什麼以及對 Fiber 的解釋,

特性概覽 —— 萬眾期待的 React 16

React 核心演算法的更新已經進行了多年了 —— 這次更新提供了一個從底層重寫了 React 的 reconciliation 演算法(譯註:reconciliation 演算法,是 React 用來比較兩棵 DOM 樹差異、從而覺得哪一部分應當被更新的演算法)。React將維護相同的公共API,並允許大多數專案立即升級(假設您已經修復了棄用警告)。新版本的釋出主要有如下目的:

  • 能夠將渲染流程中可中斷的工作(interruptible work)換劃分為一個個的 chunk。

  • 能夠為渲染流程中的工作提供優先順序劃分,rebase 以及重用能力。

  • 在渲染流程中,能夠自如地在父子元件中切換,這使得在 React 實現 layout 成為了可能。

  • 能夠從 render() 函式返回多個 element。

  • 對 error boundary 提供了更好的支援。

  • **可以在 gitconnected 上關注我 >**

特性

核心演算法重寫

這次演算法重寫帶來的主要特性是非同步渲染。(注意:在 16.0 中尚不支援,但是在未來的 16.x 版本中將會做為可選特性)。另外,新的重寫刪除了一些不成熟的、妨礙了內部變化的抽象。

這些多來自於 Lin Clark 的演講,所以你可以看看這個演講,再在 twitter 上 關注並點贊 Clark 來支援她這個視角獨特的概述。

非同步渲染的意義在於能夠將渲染任務劃分為多塊。瀏覽器的渲染引擎是單執行緒的,這意味著幾乎所有的行為都是同步發生的。React 16 使用原生的瀏覽器 API 來間歇性地檢查當前是否還有其他任務需要完成,從而實現了對主執行緒和渲染過程的管理。在 Firefox 中,一個瀏覽器主執行緒的例子很簡單:

while (!mExiting) {
    NS_ProcessNextEvent(thread);
}

在之前的版本中,React 會在計算 DOM 樹的時候鎖住整個執行緒。這個 reconciliation 的過程現在被稱作 “stack reconciliation”。儘管 React 已經是以快而聞名了,但是鎖住整個執行緒也會讓一些應用執行得不是很流暢。16 這個版本通過不要求渲染過程在初始化後一次性完成修復了該問題。React 計算了 DOM 樹的一部分,之後將暫停渲染,來看看主執行緒是否有任何的繪圖或者更新需要去完成。一旦繪圖和更新完成了,React 就會繼續渲染。這個過程通過引入了一個新的,叫做 “fiber” 的資料結構完成,fiber 對映到了一個 React 例項併為該例項管理其渲染任務,它也知道它和其他 fiber 之間的關係。一個 fiber 僅僅是一個 JavaScript 物件。下面的圖片對比了新舊渲染方法。

React 16 也會在必要的時候管理各個更新的優先順序。這就允許了高優先順序更新能夠排到佇列開頭從而被首先處理。關於此的一個例子就是按鍵輸入。鑑於應用流暢性的考慮,使用者需要立即獲得按鍵響應,因而相對於那些可以等待 100-200 毫秒的低優先順序更新任務,按鍵輸入擁有較高優先順序。

通過將 UI 的更新劃分為若干小的工作單元,使用者體驗獲得了提高。暫停 reconciliation 任務來允許主執行緒執行其他緊急的任務,這提供了更平滑的介面和可感知到的效能提升。

錯誤處理

在 React 中,錯誤總是難於處理,但在 React 16 中,一切發生了變化。之前版本中,元件內部發生的錯誤將汙染 React 的狀態,並且在後續的渲染中引起更多含義模糊的錯誤。

React 16 含有的 error boundary 不只能夠提供清晰的錯誤資訊,還能防止整個應用因錯誤而崩潰。將 error boundary 新增到你的應用之後,它能夠 catch 住錯誤並且展示一個對應的 UI 而不會造成整個元件樹崩潰。boundary 能夠在組建的渲染期、生命週期方法及所有其子樹的構造方法中 catch 錯誤。error boundary 通過一個新的生命週期方法 componentDidCatch(error, info) 就可以輕鬆實現。

class ErrorBoundary extends React.Component {
  constructor(props) {
    super(props);
    this.state = { hasError: false };
  }

  componentDidCatch(error, info) {
    // 展示一個回退 UI
    this.setState({ hasError: true });
    // 你也可以將錯誤日誌輸出到一個錯誤報告服務
    logErrorToMyService(error, info);
  }

  render() {
    if (this.state.hasError) {
      // 你可以渲染任意的自定義回退 UI
      return <h1>Something went wrong.</h1>;
    }
    return this.props.children;
  }
}

<ErrorBoundary>
  <MyWidget />
</ErrorBoundary>

在該例子中,任何發生在 <MyWidget/> 或者其子元件中的錯誤都能被 <ErrorBoundary> 元件所捕獲。這個功能類似於 JavaScript 中的 catch {} 塊。如果 error boundary 收到了一個錯誤狀態,作為開發者的你能夠確定此時應當展示的 UI。注意到 error boundary 只會 catch 其子樹的錯誤,但不會識別自身的錯誤。

進一步,你能看到如下健全的、可控的錯誤資訊:

相容性

非同步渲染

React 16.0 的初始版本將聚焦於對現有應用的相容性。非同步渲染不會再一開始作為一個可選項,但是在之後的 16.x 的版本中,非同步渲染會作為一個可選特性。

瀏覽器相容性

React 16 依賴於 Map 及 Set。為了確保對所有瀏覽器相容,你需要要引入相關 polyfill。目前流行的 polyfill 可選 core-js 或 babel-polyfill

另外,React 16 也依賴於 requestAnimationFrame,這個依賴主要服務於測試。一個針對測試目的的 shim 可以是:

global.requestAnimationFrame = function(callback) {
  setTimeout(callback);
};

元件宣告週期

由於 React 實現了渲染的優先順序設定,你無法再確保不同元件的 componentWillUpdate 和shouldComponentUpdate 會按期望的順序被呼叫。React 團隊目前正致力於提供一個更新路徑,來防止這些應用受到上面的行為的影響。

使用

截止到本文釋出,目前的 React 16 還處於 beta 版本,但是很快它就會正式釋出。你可以通過下面的方式嘗試 React 16:

# yarn
yarn add react@next react-dom@next

# npm
npm install --save react@next react-dom@next

如果你覺得本文對你很有用,請給我一個 。 在 Medium 上關注我,你能閱讀更多關於 React、Nonde.js、JavaScript 和開源軟體的文章。你也可以在 Twitter 或者 gitconnected找到我。
gitconnected —— 一個軟體開發者和工程師的社群。建立一個賬戶並登陸 gitconnected,這是一個當前最大的溝通開發者的社群。這是它的最新地址 gitconnected.com






原文釋出時間為:2017年10月11日

本文來自雲棲社群合作伙伴掘金,瞭解相關資訊可以關注掘金網站。


相關文章