一.特性
fragment
模版支持fragment和string類型,對應ReactElement數組和字符串node
v16.2.0還提供了JSX的fragment支持:<></>
error boundary
組件級錯誤處理,支持捕獲子組件樹內部異常,UI層的兜底方案react
portal
容許組件樹與DOM樹結構不一致,用於hovercards,tooltips等場景git
例如tooltip在DOM結構上target與tip通常是兄弟關係(佈局須要),而邏輯上tip是屬於target的,是父子關係,portals特性用來處理這種場景web
特殊的,事件冒泡通過處理,portals組件的父組件仍然能接到冒泡通知(React 16以前就內置了用來抹平DOM事件冒泡差別的事件系統,這裏順便支持拐彎冒泡 示例)數組
support for custom DOM attributes
以前內置了HTML/SVG屬性名白名單,自定義屬性會被攔截並忽略掉,React 16去掉了這個限制性能優化
去掉該限制有2個緣由,其一,這層內置的屬性過濾對於非標準的(好比proposal階段的)新屬性和其它庫/框架(好比Angular、Polymer)很不友好;其二,bundle裏要內置一份體積不小的屬性白名單,維護起來還挺麻煩架構
improved server-side rendering
號稱比React 15快3倍(benchmark場景,某業務場景聽說1.3倍),作了幾件事:app
支持stream框架
構建時去掉了多餘的process.env(在node環境訪問這個變量很耗時)訪問frontend
client再也不計算checksum,而是儘可能複用現有DOM(與貫徹落實DOM node複用的inferno神似,但inferno複用好像遇到一些問題,如今只做爲可選項而不是亮點特性提供)
注意:React 16貌似也存在一些DOM node複用的問題:
However, it’s dangerous to have missing nodes on the server render as this might cause sibling nodes to be created with incorrect attributes.
P.S.具體要注意哪些危險場景,官方後面可能會給出專門的博客,暫時沒有說清楚
reduced file size
React bundle瘦身(重構,扁平化打包策略,並換用rollup),體積小了30%
二.***
變化最大的應該是***,此次認真實現了一下(以前的***像是地上撿的)
1.新API
server側新增了renderToNodeStream, renderToStaticNodeStream分別對應renderToString, renderToStaticMarkup
client側新增了hydrate
2.寬鬆的一致性校驗
client側校驗沒那麼嚴格了:
React 15中,client會對拿到的***結果作字符級的一致性校驗,一點不匹配就由client從新生成並整個替掉
React 16容許屬性順序不一致,並且不給自動修復不一致的屬性,並且遇到不匹配的標籤結構,會作子樹級修改,而不是整個替掉
另外,還去掉了Server HTML結構上的checksum(data-react-checksum)以及id(data-reactid),響應體大小會下降很多:
<!-- react 15 --> <div data-reactroot="" data-reactid="1" data-react-checksum="122239856"> <!-- react-text: 2 -->This is some <!-- /react-text --> <span data-reactid="3">server-generated</span> <!-- react-text: 4--> <!-- /react-text --> <span data-reactid="5">HTML.</span> </div> <!-- react 16 --> <div data-reactroot=""> This is some <span>server-generated</span> <span>HTML.</span> </div>
3.性能優化
默認去掉了多餘的process.env.NODE_ENV訪問,不須要手動編譯去掉
***再也不建立一次性的virtual DOM,整個快了很多
支持stream,帶來的性能優點以下:
server邊造邊發,而不用等待***完畢才一次完整發過來,TTFB(the time to first byte)更快
client邊接邊畫,而不用等到響應內容完整了纔開始繪製,解析、繪製、外部資源加載等時間點都提早了
4.不支持Error Boundary和Portal
React 16 ***不支持Error Boundary和Portal
服務端子組件渲染出錯,不會被Error Boundary攔住。爲了stream性能優點,犧牲了Error Boundary:
This is intentional / a known limitation. With streaming rendering it’s impossible to 「call back」 markup that has already been sent, and we opted to keep renderToString and renderToNodeStream’s output identical.
不只renderToNodeStream, renderToStaticNodeStream不支持Error Boundary,renderToString也不支持,如上面說的,爲了保持輸出結果一致,沒有維護2套機制
P.S.關於*** Error Boundary的更多信息,請查看componentDidCatch doesn’t work in React 16’s renderToString
而Portal特性可能形成「迴流」,與Error Boundary是一個道理,在stream機制下沒法支持(想要往已經發送出去的stream裏插入Portal內容,固然不可能)
三.Fiber
全新的核心架構,(花了2年)整個重寫了組件渲染機制,最關鍵的特性是異步渲染(async rendering),實現了可調度渲染(完全解決mount流程一旦開始就沒法中斷的問題)
重構過程
這樣龐大的一個東西,傷筋動骨的重構執行過程頗有意思。簡單地說:
不拉新分支去搞。而是經過useFiber特性開關切換,說是爲了簡化平常維護/衝突處理等
第一步作個骨架(skeleton)出來。支持部分API,再慢慢跑通全部測試用例(所謂TDD,測試驅動開發,最後搞出來2000個case)
工程化輔助手段。包括進度追蹤、單測結果追蹤(便於發現一次提交修復了什麼,幹壞了什麼,手段很是簡單:把tests-failing.txt, tests-passing.txt添加到git追蹤)、持續的生產環境驗證(所謂dogfooding,從早期到最後單測經過的整個過程都在不斷地進行「實戰」驗證,算是一種看得見的信念)
找塊合適的業務做爲試驗田(testbed)。差很少穩定後,經過實際業務來證實ready for production,經過A/B測試出數據,讓2億用戶幫忙感覺一下,後來再切到全量;同時對內系統全切,擴大驗證場景;最後再對React Native應用來個灰度
不直接上新機制。暫時仍然以同步方式執行(雖然Fiber支持異步),準備再憋幾個月,好平滑過渡
P.S.具體重構過程見React 16: A look inside an API-compatible rewrite of our frontend UI library
因此暫時不支持異步渲染:
This initial React 16.0 release is mostly focused on compatibility with existing apps. It does not enable asynchronous rendering yet. We will introduce an opt-in to the async mode later during React 16.x. We don’t expect React 16.0 to make your apps significantly faster or slower, but we’d love to know if you see improvements or regressions.
優點
新特性
組件級錯誤處理、render返回多組件等以前不太容易實現的特性,重構以後均可以造出來了
體驗上的優點
Fiber並不必定更快,但會更流暢(拆分渲染任務並均衡調度,避免長時間佔用主線程),另外還有任務優先級控制,讓動畫等優先執行
差別至關明顯,見React Stack vs Fiber
參考資料
React v16.0
What’s New With Server-Side Rendering in React 16
How React Fiber can make your web and mobile apps smoother and more responsive