之前小編發過一篇類似的文章,前端面試Vue 高頻原理篇+詳細解答,還有105道vue面試題集合,整合了Vue面試題,這次整合了React面試題,兩份面試題集合都可以點擊這獲取哦
為什么選擇使用框架而不是原生?
框架的好處:
1.組件化: 其中以 React 的組件化最為徹底,甚至可以到函式級別的原子組件,高度的組件化可以是我們的工程易于維護、易于組合拓展,
2.天然分層: JQuery`時代的代碼大部分情況下是面條代碼,耦合嚴重,現代框架不管是 MVC、MVP還是MVVM 模式都能幫助我們進行分層,代碼解耦更易于讀寫,
3.生態: 現在主流前端框架都自帶生態,不管是資料流管理架構還是 UI 庫都有成熟的解決方案,
4.開發效率: 現代前端框架都默認自動更新DOM,而非我們手動操作,解放了開發者的手動DOM成本,提高開發效率,從根本上解決了UI 與狀態同步問題.
虛擬DOM的優劣如何?
優點:
- 保證性能下限: 虛擬DOM可以經過diff找出最小差異,然后批量進行patch,這種操作雖然比不上手動優化,但是比起粗暴的DOM操作性能要好很多,因此虛擬DOM可以保證性能下限
- 無需手動操作DOM: 虛擬DOM的diff和patch都是在一次更新中自動進行的,我們無需手動操作DOM,極大提高開發效率
- 跨平臺: 虛擬DOM本質上是JavaScript物件,而DOM與平臺強相關,相比之下虛擬DOM可以進行更方便地跨平臺操作,例如服務器渲染、移動端開發等等
缺點:
- 無法進行極致優化: 在一些性能要求極高的應用中虛擬DOM無法進行針對性的極致優化,比如VScode采用直接手動操作DOM的方式進行極端的性能優化
虛擬DOM實作原理?
- 虛擬DOM本質上是JavaScript物件,是對真實DOM的抽象
- 狀態變更時,記錄新樹和舊樹的差異
- 最后把差異更新到真正的dom中
React的請求應該放在哪個生命周期中?
React的異步請求到底應該放在哪個生命周期里,有人認為在componentWillMount中可以提前進行異步請求,避免白屏,其實這個觀點是有問題的.
由于JavaScript中異步事件的性質,當您啟動API呼叫時,瀏覽器會在此期間回傳執行其他作業,當React渲染一個組件時,它不會等待componentWillMount它完成任何事情 - React繼續前進并繼續render,沒有辦法“暫停”渲染以等待資料到達,
而且在componentWillMount請求會有一系列潛在的問題,首先,在服務器渲染時,如果在 componentWillMount 里獲取資料,fetch data會執行兩次,一次在服務端一次在客戶端,這造成了多余的請求,其次,在React 16進行React Fiber重寫后,componentWillMount可能在一次渲染中多次呼叫.
目前官方推薦的異步請求是在componentDidmount中進行.
如果有特殊需求需要提前請求,也可以在特殊情況下在constructor中請求:
setState到底是異步還是同步?
先給出答案: 有時表現出異步,有時表現出同步
1.setState只在合成事件和鉤子函式中是“異步”的,在原生事件和setTimeout 中都是同步的,
2.setState 的“異步”并不是說內部由異步代碼實作,其實本身執行的程序和代碼都是同步的,只是合成事件和鉤子函式的呼叫順序在更新之前,導致在合成事件和鉤子函式中沒法立馬拿到更新后的值,形成了所謂的“異步”,當然可以通過第二個引數 setState(partialState, callback) 中的callback拿到更新后的結果,
3.setState 的批量更新優化也是建立在“異步”(合成事件、鉤子函式)之上的,在原生事件和setTimeout 中不會批量更新,在“異步”中如果對同一個值進行多次setState,setState的批量更新策略會對其進行覆寫,取最后一次的執行,如果是同時setState多個不同的值,在更新時會對其進行合并批量更新,
React組件通信如何實作?
React組件間通信方式:
- 父組件向子組件通訊: 父組件可以向子組件通過傳 props 的方式,向子組件進行通訊
- 子組件向父組件通訊: props+回呼的方式,父組件向子組件傳遞props進行通訊,此props為作用域為父組件自身的函式,子組件呼叫該函式,將子組件想要傳遞的資訊,作為引數,傳遞到父組件的作用域中
- 兄弟組件通信: 找到這兩個兄弟節點共同的父節點,結合上面兩種方式由父節點轉發資訊進行通信
- 跨層級通信: Context設計目的是為了共享那些對于一個組件樹而言是“全域”的資料,例如當前認證的用戶、主題或首選語言,對于跨越多層的全域資料通過Context通信再適合不過
- 發布訂閱模式: 發布者發布事件,訂閱者監聽事件并做出反應,我們可以通過引入event模塊進行通信
- 全域狀態管理工具: 借助Redux或者Mobx等全域狀態管理工具進行通信,這種工具會維護一個全域狀態中心Store,并根據不同的事件產生新的狀態

redux的作業流程?
首先,我們看下幾個核心概念:
- Store: 保存資料的地方,你可以把它看成一個容器,整個應用只能有一個Store,
- State: Store物件包含所有資料,如果想得到某個時點的資料,就要對Store生成快照,這種時點的資料集合,就叫做State,
- Action: State的變化,會導致View的變化,但是,用戶接觸不到State,只能接觸到View,所以,State的變化必須是View導致的,Action就是View發出的通知,表示State應該要發生變化了,
- Action Creator: View要發送多少種訊息,就會有多少種Action,如果都手寫,會很麻煩,所以我們定義一個函式來生成Action,這個函式就叫Action Creator,
- Reducer: Store收到Action以后,必須給出一個新的State,這樣View才會發生變化,這種State的計算程序就叫做Reducer,Reducer是一個函式,它接受Action和當前State作為引數,回傳一個新的State,
- dispatch: 是View發出Action的唯一方法,
然后我們過下整個作業流程:
1.首先,用戶(通過View)發出Action,發出方式就用到了dispatch方法,
2.然后,Store自動呼叫Reducer,并且傳入兩個引數:當前State和收到的Action,Reducer會回傳新的State
3.State一旦有變化,Store就會呼叫監聽函式,來更新View,
到這兒為止,一次用戶互動流程結束,可以看到,在整個流程中資料都是單向流動的,這種方式保證了流程的清晰,

react-redux是如何作業的?
- Provider: Provider的作用是從最外部封裝了整個應用,并向connect模塊傳遞store
- connect: 負責連接React和Redux
1.獲取state: connect通過context獲取Provider中的store,通過store.getState()獲取整個store tree 上所有state
2.包裝原組件: 將state和action通過props的方式傳入到原組件內部wrapWithConnect回傳一個ReactComponent物件Connect,Connect重新render外部傳入的原組件WrappedComponent,并把connect中傳入的mapStateToProps, mapDispatchToProps與組件上原有的props合并后,通過屬性的方式傳給WrappedComponent
3.監聽store tree變化: connect快取了store tree中state的狀態,通過當前state狀態和變更前state狀態進行比較,從而確定是否呼叫this.setState()方法觸發Connect及其子組件的重新渲染

redux與mobx的區別?
兩者對比:
- redux將資料保存在單一的store中,mobx將資料保存在分散的多個store中
- redux使用plain object保存資料,需要手動處理變化后的操作;mobx適用observable保存資料,資料變化后自動處理回應的操作
- redux使用不可變狀態,這意味著狀態是只讀的,不能直接去修改它,而是應該回傳一個新的狀態,同時使用純函式;- - - - mobx中的狀態是可變的,可以直接對其進行修改
- mobx相對來說比較簡單,在其中有很多的抽象,mobx更多的使用面向物件的編程思維;redux會比較復雜,因為其中的函式式編程思想掌握起來不是那么容易,同時需要借助一系列的中間件來處理異步和副作用
- mobx中有更多的抽象和封裝,除錯會比較困難,同時結果也難以預測;而redux提供能夠進行時間回溯的開發工具,同時其純函式以及更少的抽象,讓除錯變得更加的容易
場景辨析:
基于以上區別,我們可以簡單得分析一下兩者的不同使用場景.
mobx更適合資料不復雜的應用: mobx難以除錯,很多狀態無法回溯,面對復雜度高的應用時,往往力不從心.
redux適合有回溯需求的應用: 比如一個畫板應用、一個表格應用,很多時候需要撤銷、重做等操作,由于redux不可變的特性,天然支持這些操作.
mobx適合短平快的專案: mobx上手簡單,樣板代碼少,可以很大程度上提高開發效率.
當然mobx和redux也并不一定是非此即彼的關系,你也可以在專案中用redux作為全域狀態管理,用mobx作為組件區域狀態管理器來用.
redux中如何進行異步操作?
當然,我們可以在componentDidmount中直接進行請求無須借助redux.
但是在一定規模的專案中,上述方法很難進行異步流的管理,通常情況下我們會借助redux的異步中間件進行異步處理.
redux異步流中間件其實有很多,但是當下主流的異步中間件只有兩種redux-thunk、redux-saga,當然redux-observable可能也有資格占據一席之地,其余的異步中間件不管是社區活躍度還是npm下載量都比較差了,
redux異步中間件之間的優劣?
redux-thunk優點:
- 體積小: redux-thunk的實作方式很簡單,只有不到20行代碼
- 使用簡單: redux-thunk沒有引入像redux-saga或者redux-observable額外的范式,上手簡單
redux-thunk缺陷:
- 樣板代碼過多: 與redux本身一樣,通常一個請求需要大量的代碼,而且很多都是重復性質的
- 耦合嚴重: 異步操作與redux的action偶合在一起,不方便管理
- 功能孱弱: 有一些實際開發中常用的功能需要自己進行封裝
redux-saga優點:
- 異步解耦: 異步操作被被轉移到單獨 saga.js 中,不再是摻雜在 action.js 或 component.js 中
action擺脫thunk function: dispatch 的引數依然是一個純粹的 action (FSA),而不是充滿 “黑魔法” thunk function - 例外處理: 受益于 generator function 的 saga 實作,代碼例外/請求失敗 都可以直接通過 try/catch 語法直接捕獲處理
- 功能強大: redux-saga提供了大量的Saga 輔助函式和Effect 創建器供開發者使用,開發者無須封裝或者簡單封裝即可使用
- 靈活: redux-saga可以將多個Saga可以串行/并行組合起來,形成一個非常實用的異步flow
易測驗,提供了各種case的測驗方案,包括mock task,分支覆寫等等
redux-saga缺陷:
- 額外的學習成本: redux-saga不僅在使用難以理解的 generator function,而且有數十個API,學習成本遠超redux-thunk,最重要的是你的額外學習成本是只服務于這個庫的,與redux-observable不同,redux-observable雖然也有額外學習成本但是背后是rxjs和一整套思想
- 體積龐大: 體積略大,代碼近2000行,min版25KB左右
- 功能過剩: 實際上并發控制等功能很難用到,但是我們依然需要引入這些代碼
- ts支持不友好: yield無法回傳TS型別
redux-observable優點:
- 功能最強: 由于背靠rxjs這個強大的回應式編程的庫,借助rxjs的運算子,你可以幾乎做任何你能想到的異步處理
- 背靠rxjs: 由于有rxjs的加持,如果你已經學習了rxjs,redux-observable的學習成本并不高,而且隨著rxjs的升級redux-observable也會變得更強大
redux-observable缺陷:
- 學習成本奇高: 如果你不會rxjs,則需要額外學習兩個復雜的庫
- 社區一般: redux-observable的下載量只有redux-saga的1/5,社區也不夠活躍,在復雜異步流中間件這個層面redux-saga仍處于領導地位
React面試題集合
基本知識
- 區分Real DOM和Virtual DOM
- 什么是React?
- React有什么特點?
- 列出React的一些主要優點,
- React有哪些限制?
- 什么是JSX?
React 組件
- 你理解“在React中,一切都是組件”這句話,
- 解釋 React 中 render() 的目的,
- 如何將兩個或多個組件嵌入到一個組件中?
- 什么是 Props?
- React中的狀態是什么?它是如何使用的?
- 區分狀態和 props
React Redux
- MVC框架的主要問題是什么?
- 解釋一下 Flux
- 什么是Redux?
- Redux遵循的三個原則是什么?
- 你對“單一事實來源”有什么理解?
- 列出 Redux 的組件,
React 路由
- 什么是React 路由?
- 為什么React Router v4中使用 switch 關鍵字 ?
- 為什么需要 React 中的路由?
- 列出 React Router 的優點,
- React Router與常規路由有何不同?


完整版的React面試題集合PDF資料直接點擊這里就可以領取了哦, 整理不易,還請點贊評論支持小編,給小編充充能量,謝謝哦!
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/289508.html
標籤:其他
