這是6月前端面試最後一篇文章了,由於個人技術棧是react,下面都是面試官面對面問的一些問題的記錄~css
MOUNTING:前端
因爲 getDefaultProps 是經過構造函數進行管理的,因此也是整個生命週期中最早開始執行的。 而 mountComponent 只能望洋興嘆, 沒法調用到 getDefaultProps。 這就解釋了爲什麼 getDefault-Props只執行一次。node
RECEIVE_PROPS:react
UNMOUNTING:webpack
組件的生命週期在不一樣狀態下的執行順序。web
絕對不要直接修改 this.state,這不只是一種低效的作法,並且頗有可能會被以後的操做替換面試
setState 經過一個隊列機制實現 state 更新。當執行 setState 時,會將須要更新的 state 合併後放入狀態隊列,而不會馬上更新 this.state,隊列機制能夠高效地批量更新 state。若是不經過 setState 而直接修改 this.state 的值,那麼該 state 將不會被放入狀態隊列中,當下次調用 setState 並對狀態隊列進行合併時,將會忽略以前直接被修改的 state,而形成沒法預知的錯誤。算法
所以,應該使用 setState 方法來更新 state,同時 React 也正是利用狀態隊列機制實現了 setState 的異步更新,避免頻繁地重複更新 state。編程
相關源碼以下:redux
// 將新的 state 合併到狀態更新隊列中
var nextState = this._processPendingState(nextProps, nextContext);
// 根據更新隊列和 shouldComponentUpdate 的狀態來判斷是否須要更新組件
var shouldUpdate = this._pendingForceUpdate ||
!inst.shouldComponentUpdate ||
inst.shouldComponentUpdate(nextProps, nextState, nextContext)
複製代碼
若是咱們在 componentWillMount 中執行 setState 方法,會發生什麼呢? 組件會更新 state,但組件只渲染一次。所以,這是無心義的執行,初始化時的 state 均可以放在 this.state。
若是咱們在 componentDidMount 中執行 setState 方法,又會發生什麼呢? 組件固然會再次更新,不過在初始化過程就渲染了兩次組件,這並非一件好事。但實際狀況是,有一些場景不得不須要 setState,好比計算組件的位置或寬高時,就不得不讓組件先渲染,更新必要的信息後,再次渲染。
若是咱們在 componentWillUnmount 中執行 setState 方法,又會發生什麼呢? 不會觸發 re-render 的,這是由於全部更新隊列和更新狀態都被重置爲null,並清除了公共類,完成了組件卸載操做
setState 循環調用風險
當調用 setState 時, 實際上會執行 enqueueSetState 方法, 並對 partialState 以及_pending- StateQueue 更新隊列進行合併操做,最終經過 enqueueUpdate 執行 state 更新。
而 performUpdateIfNecessary 方法會獲取 _pendingElement、_pendingStateQueue、_pending- ForceUpdate,並調用 receiveComponent 和 updateComponent 方法進行組件更新。
若是在 shouldComponentUpdate
或 componentWillUpdate
方法中調用 setState,此時 this._pendingStateQueue != null,則 performUpdateIfNecessary 方法就會調用 updateComponent 方法進行組件更新,但 updateComponent 方法又會調用 shouldComponentUpdate
和 componentWill- Update
方法,所以形成循環調用,使得瀏覽器內存佔滿後崩潰.以下圖
在一個父組件裏有多個子組件的時候,修改一個子組件會致使全部子組件所有從新渲染。 咱們通常都會使用shouldComponentUpdate的生命週期去判斷,可是這個生命週期是及其消耗性能的,在react裏並不推薦使用這個方法。
這個時候咱們能夠簡單的去模擬一個shouldComponentUpdate的方法。pureComponent就是在component的最外層幫咱們默認實現了一個淺比較。
React.PureComponent 與 React.Component幾乎徹底相同,但React.PureComponent經過prop和state的淺對比來實現 shouldComponentUpate()。
若是React組件的 render()函數在給定相同的props和state下渲染爲相同的結果,在某些場景下你可使用 React.PureComponent 來提高性能。
若是對象包含複雜的數據結構,它可能會因深層的數據不一致而產生錯誤的否認判斷(表現爲對象深層的數據已改變視圖卻沒有更新)。
考慮使用不可變對象
來促進嵌套數據的快速比較。此外,React.PureComponent的shouldComponentUpate() 會忽略整個組件的子級。請確保全部的子級組件也是」Pure」的
通常在componentDidMount()生命週期裏去發送一個異步請求。由於這個時候可能須要的dom已經都掛載在了瀏覽器上,咱們能夠去拿到一些咱們想要的參數,或者是把返回的數據保存在標籤中。
參考一下官方對componentDidMount的解釋
componentDidMount() is invoked immediately after a component is mounted. Initialization that requires DOM nodes should go here. If you need to load data from a remote endpoint, this is a good place to instantiate the network request.
React 組件的構建過程當中,經常有這樣的場景,有一類功能須要被不一樣的組件公用,此時就涉及抽象的話題。在不一樣的設計理念下,有許多的抽象方法,而針對 React,咱們會用到高階組件。
higher-order function(高階函數)在函數式編程中是一個基本的概念,它描述的是這樣一種函數:這種函數接受函數做爲輸入,或是輸出一個函數。好比,經常使用的工具方法 map、reduce 和 sort 等都是高階函數。 高階組件(higher-order component) ,相似於高階函數,它接受 React組件做爲輸入,輸出一個新的 React 組件。 實現高階組件的方法有以下兩種:
diff 做爲 Virtual DOM 的加速器,其算法上的改進優化是 React 整個界面渲染的基礎和性能保障, 同時也是 React 源碼中最神祕、 最難以想象的部分。 本節依然從源碼入手, 深刻剖析 diff 的難以想象之處。
下面介紹 React diff 算法的 3 個策略
其中策略三就是:element diff,當節點處於同一層級時,diff 提供了 3 種節點操做,分別爲 INSERT_MARKUP(插入) 、MOVE_ EXISTING(移動)和 REMOVE_NODE(刪除) 。
列如:舊集合中包含節點A、B、C 和 D,更新後的新集合中包含節點 B、A、D 和 C,此時新舊集合進行 diff 差別化對比,發現 B != A,則建立並插入 B 至新集合,刪除舊集合 A;以此類推,建立並插入 A、D 和 C,刪除 B、C 和 D。
針對一些都是相同的節點,但因爲位置發生變化,致使須要進行繁雜低效的刪除、建立操做,其實只要對這些節點進行位置移動便可。React 提出優化策略: 容許開發者對同一層級的同組子節點, 添加惟一 key 進行區分,雖然只是小小的改動,性能上卻發生了翻天覆地的變化!
新舊集合所包含的節點如圖所示,進行diff差別化對比後,經過key發現新舊集合中的節點都是相同的節點, 所以無需進行節點刪除和建立, 只須要將舊集合中節點的位置進行移動,更新爲新集合中節點的位置,此時 React 給出的 diff 結果爲:B、D 不作任何操做,A、C 進行移動操做便可。
combineReducers 輔助函數的做用是,把一個由多個不一樣 reducer 函數做爲 value 的 object,合併成一個最終的 reducer 函數,而後就能夠對這個 reducer 調用 createStore。
合併後的 reducer 能夠調用各個子 reducer,並把它們的結果合併成一個 state 對象。state 對象的結構由傳入的多個 reducer 的 key 決定。
最終,state 對象的結構會是這樣的:
{
reducer1: ...
reducer2: ...
}
複製代碼
經過爲傳入對象的 reducer 命名不一樣來控制 state key 的命名。例如,你能夠調用 combineReducers({ todos: myTodosReducer, counter: myCounterReducer }) 將 state 結構變爲 { todos, counter }。
一般的作法是命名 reducer,而後 state 再去分割那些信息,所以你可使用 ES6 的簡寫方法:combineReducers({ counter, todos })。這與 combineReducers({ counter: counter, todos: todos }) 同樣。
Flux 用戶使用須知 本函數能夠幫助你組織多個 reducer,使它們分別管理自身相關聯的 state。相似於 Flux 中的多個 store 分別管理不一樣的 state。在 Redux 中,只有一個 store,可是 combineReducers 讓你擁有多個 reducer,同時保持各自負責邏輯塊的獨立性。
參數 reducers (Object): 一個對象,它的值(value) 對應不一樣的 reducer 函數,這些 reducer 函數後面會被合併成一個。下面會介紹傳入 reducer 函數須要知足的規則。
返回值 (Function):一個調用 reducers 對象裏全部 reducer 的 reducer,而且構造一個與 reducers 對象結構相同的 state 對象。
注意 本函數設計的時候有點偏主觀,就是爲了不新手犯一些常見錯誤。也因些咱們故意設定一些規則,但若是你本身手動編寫根 redcuer 時並不須要遵照這些規則。
每一個傳入 combineReducers 的 reducer 都需知足如下規則:
全部未匹配到的 action,必須把它接收到的第一個參數也就是那個 state 原封不動返回。
永遠不能返回 undefined。當過早 return 時很是容易犯這個錯誤,爲了不錯誤擴散,遇到這種狀況時 combineReducers 會拋異常。
若是傳入的 state 就是 undefined,必定要返回對應 reducer 的初始 state。根據上一條規則,初始 state 禁止使用 undefined。使用 ES6 的默認參數值語法來設置初始 state 很容易,但你也能夠手動檢查第一個參數是否爲 undefined。
雖然 combineReducers 自動幫你檢查 reducer 是否符合以上規則,但你也應該牢記,並儘可能遵照。
//模擬一個combineReducers var combineReducers1 = function(obj){ //內部具體代碼 var finalState = {}; function reducer(state,action){ //reducer具體邏輯 for (var p in obj) { //根據key屬性值調用function(state.屬性名,action) finalState[p] = obj[p](state[p], action); } //返回state return finalState; } //返回最終的reducer return reducer; } 複製代碼
面對多樣的業務場景,單純地修改 dispatch 或 reducer 的代碼顯然不具備普適性,咱們須要的是能夠組合的、自由插拔的插件機制,這一點 Redux 借鑑了 Koa (它是用於構建 Web 應用的 Node.js 框架)裏 middleware 的思想。
Redux 中 reducer 更關心的是數據的轉化邏輯,因此 middleware 就是爲了加強 dispatch 而出現的。
這裏是middleware實現的源碼
export default function applyMiddleware(...middlewares) { return (next) => (reducer, initialState) => { let store = next(reducer, initialState); let dispatch = store.dispatch; let chain = []; var middlewareAPI = { getState: store.getState, dispatch: (action) => dispatch(action), }; chain = middlewares.map(middleware => middleware(middlewareAPI)); dispatch = compose(...chain)(store.dispatch); return { ...store, dispatch, }; } } 複製代碼
源碼我就不解析了,這個源碼我少說看了5遍,一直理解都不到位,精髓難懂啊
webpack的打包原理是:1.一切皆是模塊。給定一個主體文件(列如index.js),而後從這個主js中開始去招全部依賴的js,css,img等經過loader把他們都解析成模塊輸出。
與gulp有什麼區別。
由於用過gulp,他的配置是任務,列task
,好比js壓縮,解析。相似於對less或sass的編譯,組合,對圖片的壓縮,gulp就是提供一個流程化的一個工具。還能夠在webpack前先執行gulp作一些流程化的配置,而後用gulp把webpack跑起來~
這個問題基本上是百分之百必問,我以爲,能夠在本身的項目裏找一個即記憶猶新又能突出難點而且本身掌握的問題去說明~ 太簡單又突出不了各位的實力,太難了還沒掌握的面試官一深挖就暴露了,哈哈哈哈
很是感謝 《深刻React技術棧》做者:陳屹 這本書,讓我在react的道路真的學到了不少~推薦~
友情連接: