React面試指南

Reac知識圖譜react

1、React基礎使用

1. React中數據通訊有哪些方式

  • 簡單層級傳遞,如父子,可使用props。算法

    <Child title="數據"/>
    複製代碼
  • 祖先與子孫,跨層級數據傳遞或者兄弟組件通訊:Context、第三方狀態管理庫如redux、mobx等。redux

2. 如何使用跨層級數據傳遞

  • 建立Context對象
const TheContext = React.createContext();
複製代碼
  • 使用Context Provider傳遞value
<TheContext.Provider>
	<Child/>
</TheContext.Provider>
複製代碼
  • Provider的子孫組件消費value:contextType(只能用在類組件中且只能訂閱單一context來源)、useContext(hook函數,只能用在函數組件或者自定義hook中)、Consumer。
//contextType
class Child extends Component {
  contextType = TheContext;
  componentDidMount() {
    console.log(this.context); //sy-log
  }
  render() {
    return <div>呵呵呵</div>;
  }
}
//useContext
function Child(props) {
  const context = useContext(TheContext);
  console.log(context); //sy-log
  return <div>哈哈哈</div>;
}
//Consumer 函數類組件均可
function Child(props) {
  return (
    <div> <TheContext.Consumer> {(context) => { console.log(context); //sy-log return <div>嗯嗯嗯</div>; }} </TheContext.Consumer> </div>
  );
}
複製代碼

3. 類組件中的setState如何使用

setState(updater, [callback]);
複製代碼

update:object | function。若是是object,則會與類組件中上次的state對象合併,若是是函數,(prevState, nextProps)=>{ return newState };數組

callback:可選,回調函數。markdown

類組件中的setState是批量更新,即咱們常說的異步。可是在原生事件和setTimeout中是同步的。react-router

2、React原理

1. key值有什麼用?

key標記了節點在當前層級下的惟一性,和組件類型一塊兒用於diff時候判斷節點是否能夠複用、是否要刪除、是否要新增。dom

2. setState是同步仍是異步

有時表現出異步,有時表現出同步。異步

  • setState在合成事件和鉤子函數中是異步的,在原生事件和 setTimeout 中是同步的。
  • 這裏的異步並非說setState內部由異步代碼實現,而是指setState的更新是批量更新,也就是說合成事件和鉤子函數是在state更新以前就調用了,致使沒法當即取到state更新以後的值,固然若是你須要再state更新以後作某些操做,則可使用setState(partialState, callback)的callback參數。
  • setState在原生事件中是同步的,主要是由於React源碼沒法肯定原生事件是何時註冊的,不像合成事件,組件渲染的時候就能夠經過合成事件的映射表得知。
  • 而若是setState定義在setTimeout中,因爲setTimeout自己就是異步,就算是合成事件,等setTimeout裏的setState要執行的時候,批量更新的標記也已經失效了,所以表現出來的依然是同步。

3. 什麼fiber

fiber在React源碼中表現爲一個節點對象,仍然是虛擬dom,表現爲單鏈表結構。其中child屬性是第一個子fiber節點,sibling是下一個兄弟節點。ide

  • 在React16以前,React組件的子組件是一個children數組,而這些子組件的遞歸渲染只和children數組中的下標位置相關。
  • 對於大型項目來講,組件樹會很是大,那麼遞歸遍歷也就會很是耗時耗力,這個時候一些較高優先級的任務,如動畫任務、和用戶交互的任務(如input的onChange)等就應該被早點執行,否則用戶可能就會看到卡頓的現象,這對用戶體驗是極其不利的。
  • 爲了要解決上面的問題,能夠給不一樣的任務添加優先級。要作到這一點,首先節點的顆粒度也要夠小,這就是後來出現的fiber節點。
  • 再者,若是一個任務a正在執行,可是這個時候來了更高優先級的任務b,那就要中斷a,去執行b。也就是說,任務是須要可中斷的。而且,被迫中斷的a並非要被拋棄掉,可能執行完b之後仍是要再執行a的,那這個時候就須要a和b之間有個指針關係,否則執行完b了,怎麼能找到a呢?因此fiber是個單鏈表結構。

4. 說說react中的diff

算法複雜度:O(n)函數

React中這個diff算法複雜度的前提是:深度優先遍歷、同級比較、只有key值和類型徹底相同的組件才能夠複用。

接下來如下圖爲例,來講一下React diff的流程:

image-20191022194524132

假設上面的樹爲老的虛擬dom節點,下面的樹爲新的虛擬dom節點,圓形和多邊形節點標識不一樣的組件類型,大寫字母標識節點的key。

  • 按照深度優先遍歷,先A再B,而後D,可是兩個新老樹裏D組件類型不一樣,老E和新D的key不一樣,都沒法複用,所以新增新D。
  • 新的D節點沒有子節點,所以下一步是G節點。雖然老樹裏有G節點,可是和新樹裏的G節點不是同一層級,所以沒法複用。所以新G須要新增。
  • 這樣新樹B節點下的DG都須要新增,老樹下的DE都須要被刪除。
  • 新樹的G節點沒有子節點和兄弟節點,而後經過G的爸爸B節點找到叔叔C節點,新老樹下都有C節點,而且同一層級下,能夠複用,雖然相對位置不一樣,可是不要緊能夠移動位置。
  • 老C下有G,新C的沒有,則老樹的C須要被刪除。
  • 新C沒有子節點,下一步是兄弟H節點,這個時候新老H的key和組件類型都相同,仍是同一層級下,所以複用就能夠了。
  • OVER。

3、狀態管理庫

React知識圖譜

1. 爲何要使用狀態管理庫

目前任何一個狀態管理庫都不是強制使用的,也有不少精小的項目不使用第三方狀態管理庫,而只是使用React自身的state、useContext等API就能夠達到目的。固然,對於大型項目,仍是建議使用一個狀態管理庫,畢竟項目越大,須要管理、共享的狀態越多,這個時候爲了不data層與view層變成一鍋粥,仍是使用個狀態管理庫吧。

2. React目前常見的狀態管理庫有哪些,比較一下

redux、mobx、recoil(實驗階段)。

  • redux是集中式管理state,而recoil和mobx都是分散式。
  • recoil中狀態的讀寫都是Hooks函數,目前沒有提供類組件的使用方式。
  • recoil是Facebook開發的,可使用React內部的調度機制,這是redux和mobx不支持的。
  • recoil目前仍是實驗階段,想要應用到的本身的項目中,等待正式版發了再說吧。

3. redux如何實現異步

redux自己是不支持異步的,可使用中間件,redux-thunk、redux-saga。

4、路由管理庫

1. Route渲染組件有哪些方式?

Route有三種互斥的組件渲染方式,按照優先級高低分別是children、component、render。

2. Route渲染組件的三種方式,有什麼不一樣?

children是不論是否匹配都會渲染,而component和render都是匹配了纔會渲染。另外,children和render的參數是函數,而component的參數是React組件。

當你用component的時候,Route會用你指定的組件和React.createElement建立一個新的[React element]。這意味着當你提供的是一個內聯函數的時候,每次render都會建立一個新的組件。這會致使再也不更新已經現有組件,而是直接卸載而後再去掛載一個新的組件。所以,當用到內聯函數的內聯渲染時,請使用render或者children。

react-router中Route的render源碼以下:

image-20200224174023810

相關文章
相關標籤/搜索