React 16 帶來了什麼以及對 Fiber 的解釋:特性概覽 — 萬眾期待的 React 16

原文地址:What』s New in React 16 and Fiber Explanation

原文作者:Trey Huffine

譯文出自:掘金翻譯計劃

本文永久鏈接:github.com/xitu/gold-mi

譯者:yoyoyohamapi

校對者:Tina92 sunui

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 對象。下面的圖片對比了新舊渲染方法。

Stack reconciliation — updates must be completed entirely before returning to main thread (credit Lin Clark)

Fiber reconciliation — updates will be batched in chunks and React will manage the main thread (credit Lin Clark)

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

React priorities (credit Lin Clark)

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

錯誤處理

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

lol wut?

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 其子樹的錯誤,但不會識別自身的錯誤。

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

omg that』s nice (credit Facebook)

兼容性

非同步渲染

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:

# yarnyarn add react@next react-dom@next# npmnpm install --save react@next react-dom@next

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


掘金翻譯計劃 是一個翻譯優質互聯網技術文章的社區,文章來源為 掘金 上的英文分享文章。內容覆蓋 Android、iOS、React、前端、後端、產品、設計 等領域,想要查看更多優質譯文請持續關注 掘金翻譯計劃、官方微博、知乎專欄。

推薦閱讀:

有關Bootstrap你想要知道的都在這裡
【React/Redux】深入理解React服務端渲染
讓你的Web項目好看起來!
到底如何使用jekyll發布博客?

TAG:React | 前端开发 | 前端框架 |