本篇文章會列舉 react 的全部常見面試問題. 並附上詳細解答.若是你想更深刻的瞭解底層原理, 可到文末的建議閱讀中查找.javascript
詳細的內容請見另外一篇文章: 面試官: 談一談 HOC、Render props、Hookshtml
在 React 中, React 會先將代碼轉換成一個 JS 對象, 而後再將這個 JS 對象轉換成真正的 DOM. 這個 JS 對象就是所謂的虛擬 DOM.java
它可讓咱們無須關注 DOM 操做, 只須要開心地編寫數據,狀態便可.react
爲何是 O(n^3) ? 從一棵樹轉化爲另一棵樹,直觀的方式是用動態規劃,經過這種記憶化搜索減小時間複雜度。因爲樹是一種遞歸的數據結構,所以最簡單的樹的比較算法是遞歸處理。確切地說,樹的最小距離編輯算法的時間複雜度是 O(n^2m(1+logmn)), 咱們假設 m 與 n 同階, 就會變成 O(n^3)。git
爲何是 O(n^3)github
react diff 原理面試
簡單的來說, react 它只比較同一層, 一旦不同, 就刪除. 這樣子每個節點只會比較一次, 因此算法就變成了 O(n).算法
對於同一層的一組子節點. 他們有可能順序發生變化, 可是內容沒有變化. react 根據 key 值來進行區分, 一旦 key 值相同, 就直接返回以前的組件, 不從新建立.數組
這也是爲何渲染數組的時候, 沒有加 key 值或者出現重複key值會出現一些奇奇怪怪的 bug .瀏覽器
除了 key , 還提供了選擇性子樹渲染。開發人員能夠重寫 shouldComponentUpdate 提升 diff 的性能。
<div>Hello ConardLi</div>
複製代碼
實際上, babel 幫咱們將這個語法轉換成
React.createElement('div', null, `Hello ConardLi`)
複製代碼
自定義組件必須大寫的緣由. babel 在編譯的過程當中會判斷 JSX 組件的首字母, 若是是小寫, 則爲原生 DOM 標籤, 就編譯成字符串. 若是是大寫, 則認爲是自定義組件. 編譯成對象.
爲何如下代碼會報錯?
return (<a></a><a></a>)
複製代碼
一樣的, 由於咱們是按照 React.createElement() 來建立組件, 因此只能有一個根節點. 若是你想要使用 2 個平行的節點, 能夠用 <></> 來包裹. <></> 會被編譯成 <React.Fragment/>.
babel 轉譯以下:
本身動手玩一下轉換, 加深印象吧~
這裏的「異步」不是說異步代碼實現. 而是說 react 會先收集變動,而後再進行統一的更新.
setState 在原生事件和 setTimeout 中都是同步的. 在合成事件和鉤子函數中是異步的.
在 setState 中, 會根據一個 isBatchingUpdates 判斷是直接更新仍是稍後更新, 它的默認值是 false. 可是 React 在調用事件處理函數以前會先調用 batchedUpdates 這個函數, batchedUpdates 函數 會將 isBatchingUpdates 設置爲 true. 所以, 由 react 控制的事件處理過程, 就變成了異步(批量更新).
咱們先看看 冒泡捕獲 的經典圖:
在組件掛載的階段, 根據組件生命的 react 事件, 給 document 添加事件 addEventListener, 並添加統一的事件處理函數 dispatchEvent.
將全部的事件和事件類型以及 react 組件進行關聯, 將這個關係保存在一個 map 裏. 當事件觸發的時候, 首先生成合成事件, 根據組件 id 和事件類型找到對應的事件函數, 模擬捕獲流程, 而後依次觸發對應的函數.
若是原生事件使用 stopPropagation 阻止了冒泡, 那麼合成事件也被阻止了.
React 事件機制跟原生事件有什麼區別 React 的事件使用駝峯命名, 跟原生的所有小寫作區分. 不能經過 return false 來阻止默認行爲, 必須明確調用 preventDefault 去阻止瀏覽器的默認響應.
背景: 因爲瀏覽器它將 GUI 描繪,時間器處理,事件處理,JS 執行,遠程資源加載通通放在一塊兒。若是執行 js 的更新, 佔用了過久的進程就會致使瀏覽器的動畫沒辦法執行,或者 input 響應比較慢。
react fiber 使用了 2 個核心解決思想:
一次更新過程會分爲不少個分片完成, 因此可能一個任務尚未執行完, 就被另外一個優先級更高的更新過程打斷, 這時候, 低優先級的工做就徹底做廢, 而後等待機會重頭到來.
requestIdleCallback
首先 react 會根據任務的優先級去分配各自的過時時間 expriationTime . requestIdleCallback 在每一幀的多餘時間(黃色的區域)調用. 調用 channel.port1.onmessage , 先去判斷當前時間是否小於下一幀時間, 若是小於則表明咱們有空餘時間去執行任務, 若是大於就去執行過時任務,若是任務沒過時. 這個任務就被丟到下一幀執行了.
因爲 requestIdleCallback 的兼容性問題, react 本身實現了一個 requestIdleCallback
事實上, 這並不算是 react 的問題, 而是 this 的問題. 可是也是 react 中常常出現的問題. 所以也講一下
<button type="button" onClick={this.handleClick}>Click Me</button>
複製代碼
這裏的 this . 當事件被觸發且調用時, 由於 this 是在運行中進行綁定的.his 的值會回退到默認綁定,即值爲 undefined,這是由於類聲明和原型方法是以嚴格模式運行。
咱們可使用 bind 綁定到組件實例上. 而不用擔憂它的上下文.
由於箭頭函數中的 this 指向的是定義時的 this,而不是執行時的 this. 因此箭頭函數一樣也能夠解決.