React16.x特性剪輯
本文整理了 React 16.x 出現的耳目一新的概念與 api 以及應用場景。
更多 React 系列文章可以訂閱 ofollow,noindex" target="_blank">blog
16.0 Fiber
在 16 之前的版本的渲染過程可以想象成一次性潛水 30 米,在這期間做不了其它事情(Stack Reconciler);
痛點概括:
- 一次性渲染到底
- 中途遇到優先順序更高的事件無法調整相應的順序
在 16 版本上, React 帶來了 Fiber 的架構, 接著拿上面的潛水例子為例,現在變為可以每次潛 10 米,分 3 個 chunk 進行; chunk 和 chunk 之間通過連結串列連線; chunk 間插入優先順序更高的任務, 先前的任務被拋棄。
開啟 Fiber 後,獲取非同步資料的方法應放到 render 後面的生命週期鉤子裡(phase 2 階段)進行, 因為 render 前面的生命週期鉤子(phase 1階段)會被執行多次
注意: 並沒有縮短原先元件的渲染時間(甚至還加長了),但使用者卻能感覺操作變流暢了。
render()
在 React16 版本中 render() 增加了一些返回型別,到目前為止支援的返回型別如下:
- React elements.
- Arrays and fragments.
- Portals.
- String and numbers.
- Booleans or null.
其中 render() 支援返回 Arrays 能讓我們少寫一個父節點, 如下所示:
const renderArray = () => [ <div>A</div> <div>B</div> ]
個人認為 render() 支援返回陣列完全可以取代 Fragments
Portals(傳送門)
將 react 子節點渲染到指定的節點上
案例:實現一個 Modal 元件, demo
另外關於 Portals 做到冒泡到父節點的兄弟節點這個現象, demo , 我想可以這樣子實現:如果元件返回是 Portal 物件,則將該元件的父元件的上的事件 copy 到該元件上。其實並不是真的冒泡到了父節點的兄弟節點上。
Error Boundaries
React 16 提供了一個新的錯誤捕獲鉤子 componentDidCatch(error, errorInfo)
, 它能將子元件生命週期裡所丟擲的錯誤捕獲, 防止頁面全域性崩潰。 demo
componentDidCatch 並不會捕獲以下幾種錯誤
- 事件機制丟擲的錯誤(事件裡的錯誤並不會影響渲染)
- Error Boundaries 自身丟擲的錯誤
- 非同步產生的錯誤
- 服務端渲染
服務端渲染
服務端渲染一般是作為最後的優化手段, 這裡淺顯(缺乏經驗)談下 React 16 在其上的優化。
在 React 16 版本中引入了 React.hydrate()
, 它的作用主要是將相關的事件 注水
進 html
頁面中, 同時會比較前端生成的 html
和服務端傳到前端的 html
的文字內容的差異, 如果兩者不一致將前端產生的文字內容替換服務端生成的(忽略屬性)。
支援自定義屬性
在 React 16 版本中, 支援自定義屬性(推薦 data-xxx
), 因而 React 可以少維護一份 attribute 白名單, 這也是 React 16 體積減少的一個重要因素。
life cycle
在 React 16.3 的版本中,新加入了兩個生命週期:
-
getDerivedStateFromProps(nextProps, prevState)
: 更加語義化, 用來替代 componentWillMount、componentWillReceiveProps(nextProps); -
getSnapshotBeforeUpdate(prevProps, prevState)
: 可以將結果傳入 componentDidUpdate 裡, 從而達到 dom 資料統一。用來替代 componentWillUpdate()(缺點是 React 開啟非同步渲染後,componentWillUpdate() 與 componentDidUpdate() 間獲取的 dom 會不統一;
16.7 Hooks
在 React 16.7 之前,React 有兩種形式的元件,有狀態元件(類)和無狀態元件(函式)。Hooks 的意義就是賦能先前的無狀態元件,讓之變為有狀態。這樣一來更加契合了 React 所推崇的函數語言程式設計。
接下來梳理 Hooks 中最核心的 2 個 api, useState
和 useEffect
useState
useState 返回狀態和一個更新狀態的函式
const [count, setCount] = useState(initialState)
使用 Hooks 相比之前用 class 的寫法最直觀的感受是更為簡潔
function App() { const [count, setCount] = useState(0) return ( <div> <p>You clicked {count} times</p> <button onClick={() => setCount(count + 1)}> Click me </button> </div> ) }
useEffect(fn)
在每次 render 後都會執行這個鉤子。可以將它當成是 componentDidMount
、 componentDidUpdate
、 componentWillUnmount
的合集。因此使用 useEffect 比之前優越的地方在於:
componentDidMount、componentDidUpdate useEffect
在上述提到的生命週期鉤子之外,其它的鉤子是否在 hooks 也有對應的方案或者捨棄了其它生命週期鉤子, 後續進行觀望。