react相關面試題

React 的核心流程能夠分爲兩個部分:javascript

reconciliation (調度算法,也可稱爲 render): // 調和前端

    更新 state 與 props;java

    調用生命週期鉤子;react

    生成 virtual dom;算法

    這裏應該稱爲 Fiber Tree 更爲符合;redux

    經過新舊 vdom 進行 diff 算法,獲取 vdom change;數組

    肯定是否須要從新渲染瀏覽器

  commit:性能優化

    如須要,則操做 dom 節點更新;babel

 

 

constructor ====》 初始化state
componentWillMount  ==== 》 // 當新 props 中的 data 發生變化時,同步更新到 state 上
componentDidMount ====》進行事件監聽,數據的請求
componentWillUpdate === 》 getSnapshotBeforeUpdate componentDidUpdate ==== 》 當 id 發生變化時,從新獲取數據 shouldComponentUpdate ====》 優化渲染的性能,return false 阻止後面的邏輯 componentWillReciveProps ==== 》少使用,使用  componentWillUnmount ====》 解綁事件getDerivedStateFromPropsgetDerivedStateFromProps

在新版本中,React 官方對生命週期有了新的 變更建議:

  • 使用getDerivedStateFromProps 替換componentWillMount
  • 使用getSnapshotBeforeUpdate替換componentWillUpdate
  • 避免使用componentWillReceiveProps

其實該變更的緣由,正是因爲上述提到的 Fiber。首先,從上面咱們知道 React 能夠分紅 reconciliation 與 commit 兩個階段,對應的生命週期以下:

  • reconciliation:

    • componentWillMount
    • componentWillReceiveProps
    • shouldComponentUpdate
    • componentWillUpdate
  • commit:

    • componentDidMount
    • componentDidUpdate
    • componentWillUnmount

在 Fiber 中,reconciliation 階段進行了任務分割,涉及到 暫停 和 重啓,所以可能會致使 reconciliation 中的生命週期函數在一次更新渲染循環中被 屢次調用 的狀況,產生一些意外錯誤。

新版的建議生命週期以下:

class Component extends React.Component {
  // 替換 `componentWillReceiveProps` ,
  // 初始化和 update 時被調用
  // 靜態函數,沒法使用 this
  static getDerivedStateFromProps(nextProps, prevState) {}
  
  // 判斷是否須要更新組件
  // 能夠用於組件性能優化
  shouldComponentUpdate(nextProps, nextState) {}
  
  // 組件被掛載後觸發
  componentDidMount() {}
  
  // 替換 componentWillUpdate
  // 能夠在更新以前獲取最新 dom 數據
  getSnapshotBeforeUpdate() {}
  
  // 組件更新後調用
  componentDidUpdate() {}
  
  // 組件即將銷燬
  componentWillUnmount() {}
  
  // 組件已銷燬
  componentDidUnMount() {}
}

  使用建議:

  • constructor初始化 state;
  • componentDidMount中進行事件監聽,並在componentWillUnmount中解綁事件;
  • componentDidMount中進行數據的請求,而不是在componentWillMount
  • 須要根據 props 更新 state 時,使用getDerivedStateFromProps(nextProps, prevState)
    • 舊 props 須要本身存儲,以便比較;
    • public static getDerivedStateFromProps(nextProps, prevState) {
      	// 當新 props 中的 data 發生變化時,同步更新到 state 上
      	if (nextProps.data !== prevState.data) {
      		return {
      			data: nextProps.data
      		}
      	} else {
      		return null1
      	}
      }

        

  • 能夠在componentDidUpdate監聽 props 或者 state 的變化,例如:
componentDidUpdate(prevProps) {
	// 當 id 發生變化時,從新獲取數據
	if (this.props.id !== prevProps.id) {
		this.fetchData(this.props.id);
	}
}

 

  • componentDidUpdate使用setState時,必須加條件,不然將進入死循環;
  • getSnapshotBeforeUpdate(prevProps, prevState)能夠在更新以前獲取最新的渲染數據,它的調用是在 render 以後, update 以前;
  • shouldComponentUpdate: 默認每次調用setState,必定會最終走到 diff 階段,但能夠經過shouldComponentUpdate的生命鉤子返回false來直接阻止後面的邏輯執行,一般是用於作條件渲染,優化渲染的性能。

二: 虛擬DOM的理解

  (1)Virtual DOM是對DOM的抽象,本質上是JavaScript對象,這個對象就是更加輕量級的對DOM的描述.

    (2)兩個內容的差別,進行dom的對比,事件屬性方法,耗性能,dom對象轉換爲js對象,比較會快。有效提高性能。

  (3)首先,咱們都知道在前端性能優化的一個祕訣就是儘量少地操做DOM,不只僅是DOM相對較慢,更由於頻繁變更DOM會形成瀏覽器的迴流或者重回,這些都是性能的殺手,所以咱們須要這一層抽象,在patch過程當中儘量地一次性將差別更新到DOM中,這樣保證了DOM不會出現性能不好的狀況.

    (4)更好的跨平臺,好比Node.js就沒有DOM,若是想實現SSR(服務端渲染),那麼一個方式就是藉助Virtual DOM,由於Virtual DOM自己是JavaScript對象.

三:diff算法

  (1)diff的目的就是比較新舊Virtual DOM Tree找出差別並更新.

  (2)一層節點發現有問題,再也不往下比,直接放棄,n的平方下降爲n

  • 把樹形結構按照層級分解,只比較同級元素(層級比較)
  • 給列表結構的每一個單元添加惟一的 key 屬性,方便比較(列表添加key)
  • React 只會匹配相同 class 的 component(這裏面的 class 指的是組件的名字)
  • 選擇性子樹渲染。開發人員能夠重寫shouldComponentUpdate 提升 diff 的性能

四:key值的做用

  (1)若是key值相同,dom直接複用,不用再建立dom,直接這兩個比,不用循環比

  (2)用新指針對應節點的key去舊數組尋找對應的節點,這裏分三種狀況,

      當沒有對應的key,那麼建立新的節點,

      若是有key而且是相同的節點,把新節點patch到舊節點,

      若是有key可是不是相同的節點,則建立新節點

五:怎麼理解HOC高階組件

   接收一些函數,返回函數,組件進行包裝,返回一個新的組件,不少地方都要用,有一點區別,共用的東西寫在高階組件中,經過傳遞額外參數,動態改變組件不一樣場景下使用的差別。

六:redux中間件的原理

  action--store-reducer-props   action和store之間,溝通的橋樑dispatch,改裝dispatch,

  store.dispatch,直接把action(對象)傳遞給store,使用中間件,action能夠是函數,能夠將函數轉換爲對象,傳遞給store。

七:setState發生了什麼?遇到過什麼坑

  調和的過程。setState通常怎麼用,傳遞什麼進去,對象仍是方法。

this.setState({
    name: '小李'
});
this.setState(() =>({
    name:'小李'
}));
永遠用函數調用,會避免一些坑。
this.setState({
    age: this.state.age+1
});
setState異步,瘋狂點擊按鈕,age不是每次加1,會一次加5,6個,state異步,會進行累加
<input  refs="input"  value={this.state.age} />  ====1 
this.setState((prevState) =>{
    age: ++ prevState
});
this.refs.input.value  ==== 1
this.setState((prevState) =>{
    age: ++ prevState
}, () => {
    this.refs.input.value  // 異步執行完state以後執行
});

 

八:ref是一個函數,有什麼好處?

  方便react在銷燬組件從新渲染,有效清空ref引用中的東西,防止內存泄漏

九:refs做用是什麼,在什麼場景下用過?

  操做dom(滾動條,點擊按鈕,滾動條滾動到上面)

  圖片展現獲取圖片的寬和高,

 

十:react中this的指向問題

  

十一:react-router的實現原理

hash/location

十二:jsx代碼的轉化(babel)

createElement

十三:受控組件和非受控組件

受控:有生命週期

非受控:純函數

十四:函數組件怎麼作性能優化

 

十五:react-saga的設計思想

改裝dispatch   action-----store之間,action能夠是一個函數,能夠執行異步操做

十六:組件是什麼?類是什麼?類被編譯成什麼?

十七:reselect是作什麼使用的?

十八:何時使用異步組件?

十九:xss攻擊,react如何防範?

二十:react怎麼提升性能優化?

shouldComponentUpdate

pureComponent

二十一:ssr

二十二:

  • 爲何返回多個標籤或組件必需要用一個標籤或組件包裹?
  • 爲何在根本沒有使用React這個變量的狀況下還要import React

整個UI其實是經過層層嵌套的React.createElement方法返回的,因此咱們要在文件開頭import React,不然編譯後就會發現createElement沒有定義。

React.createElement執行的結果是一個對象,對象的屬性描述了標籤或組件的性狀,對象再嵌套子對象。若是頂層返回多個標籤,就沒法表達爲一個對象了

相關文章
相關標籤/搜索