因為最近想準備面試,所以整理了些覺得算是比較進階的 React 必備知識,底下是 9 個問題和回答:
元件中週期有哪些? 執行順序如何?
人有生老病死,元件從出現到消失主要也分三部分 Mount -> Updating -> Unmounting:
Mount: 已經出現在瀏覽器的 DOM 上
constructor()
static getDerivedStateFromProps()
render()
componentDidMount()
Updating: Props 或 State 變化後引發的元件更新
getDerivedStateFromProps()
shouldComponentUpdate()
render()
getSnapshotBeforeUpdate()
componentDidUpdate()
Unmounting: 從瀏覽器的 DOM 中移除
componentWillUnmount()
getDerivedStateFromProps()
這個週期的用途?
getDerivedStateFromProps()
會在元件初始化後但尚未 re-rendered 前執行。會回傳一個物件去更新狀態或是也可以選擇回傳 null
代表這次的 props 改變不用更新元件狀態,搭配 componentDidUpdate()
一起使用來取代被棄用的componentWillReceiveProps()
。
1 | class MyComponent extends React.Component { |
元件渲染的三個狀態
元件從 Props 或 State 變化後引發改變的過程,主要分為兩大階段 Render 和 Commit,會先進行 Render 的計算後才會真的 Commit 結果到真正的 DOM 上面,Commit 前會有個 Pre-commit。
- Render: 在這個階段 React 能自行暫停、取消、重新這個過程
- Pre-commit: 文件上有出現但甚少使用的功能,有一個週期是
getSnapshotBeforeUpdate()
,可以看成是一個做決定前的再次狀態確認 - Commit: 套用改變到瀏覽器的 DOM 上,而這是肉眼可見,也是我們較常操作的週期
componentDidMount()
: Mount 成功,出現在 DOM 上面componentDidUpdate()
: Props 或 State 改變componentWillUnmount()
: 從 DOM 上移除
什麼是 Reconciliation?
當元件 props 或是 state 改變後,React 會透過 render 的演算法來決定最終要更新到 DOM 上面的改變,這個過程就是 reconciliation。
如果是想自己手動提升效能則可以運用條件減少狀態改變:
1 | getUserAddress = (user) => { |
什麼是 HOC (Higher-Order Components)?
常寫 JavaScript 的開發者就會知道,function 可以 return 任何東西,而 return 一個新的 function 的 function 我們就稱作 HOF (Higher-Order Function),底下是範例:
1 | var xHOF = function (x) { |
一個 HOC 就是一個函式 (function),接收到元件後,產生出另一個新的元件,在卡通影片中,可以想像成金剛戰士透過手表進行變身,或是數碼寶貝透過共振主人的無限可能進化成更強的模樣。一個 HOC 有底下四個特點:
- Pure component: 沒有修改原來行為只有加強功能
- Code reuse: 讓邏輯能夠重複使用
- Render hijacking: 在真的元件 render 前,處理 render 前需要處理的事情,像是資料防呆或是將操作記錄發到後台
- Manipulation: State 和 Props 統一控制,元件載入狀態動畫
1 | function HOC(WrappedComponent) { |
有 staticMethod 的話要自己複製:
1 | function enhance(WrappedComponent) { |
React 中的 Portals 是做什麼用的?
正常 react 所有的渲染都只掛載在某個 Parent 節點下,如果需要跳脫這個節點就需要 Portals,第一個參數可以放任何可被渲染的 child,第二個參數則是真實的 DOM element。
ReactDOM.createPortal(child, container)
React v16 錯誤邊界 (Error Boundaries) 是什麼?
錯誤邊界其實也只是個元件,錯誤邊界的概念像是一道防火門,讓當渲染發生錯誤時,能夠被關在 child component 中並顯示客製化的錯誤 UI,透過 componentDidCatch(error, info)
或 static getDerivedStateFromError()
這兩個新增的周期來協助記錄相關錯誤。
This lifecycle method is invoked after an error has been thrown by a descendant component. It receives the error that was thrown as a parameter and should return a value to update state.
The signature of the lifecycle method is as follows,
static getDerivedStateFromError(error)
1 | class ErrorBoundary extends React.Component { |
當撰寫完成後,使用上也非常簡單,只要把原來的元件包起來就好了,底下是範例
1 | <ErrorBoundary> |
錯誤邊界在底下四種情形不會 catch 到錯誤
- 在 Event handlers 中,只能夠自己寫 try catch
- setTimeout 或 requestAnimationFrame 的 callbacks
- 伺服器渲染的過程
- ErrorBoundary 沒寫好自己發生的錯誤
1 | class MyComponent extends React.Component { |
React 中要怎麼實作 Props 相關檢查?
雖然 JavaScript 是弱型別的語言,但 React 內建 PropTypes check 機制,當 APP 處在開發模式下,React 會自動確認是否每個 props 都是如所設定的格式,若不正確 React 就會在命令列中產生警告的訊息,這個機制由於效能考量在 Production 環境中會被停用。
React 定義了底下十種型別:
PropTypes.number
PropTypes.string
PropTypes.array
PropTypes.object
PropTypes.func
PropTypes.node
PropTypes.element
PropTypes.bool
PropTypes.symbol
PropTypes.any
Props 中可分為必填和非必填,必填的後面則加上 isRequired
像是 PropTypes.number.isRequired
,如果陣列中的物件需要定義則可以搭配使用 React.PropTypes.shape()
和 React.PropTypes.arrayOf()
,如果 Props 會是變動的,也可以使用 React.PropTypes.oneOfType()
。
1 | ReactComponent.propTypes = { |
如何在頁面載入時自動 focus 在輸入框上?
只需要幫 input
加上參照 ref
就可以在 componentDidMount()
後針對 input
進行操作。不過這種 inline function 的寫法在元件更新的時候因為底層的邏輯會被執行兩次,所以不被推薦。
1 | class App extends React.Component { |
比較推薦的寫法如下:
1 | class UserForm extends Component { |
喜歡這篇文章,請幫忙拍拍手喔 🤣