關於React面試題彙總

常見的中間件:html

redux-logger:提供日誌輸出react

redux-thunk:處理異步操做算法

redux-promise:處理異步操做,actionCreator的返回值是promiseredux

 

二、redux有什麼缺點segmentfault

1.一個組件所須要的數據,必須由父組件傳過來,而不能像flux中直接從store取。數組

2.當一個組件相關數據更新時,即便父組件不須要用到這個組件,父組件仍是會從新render,可能會有效率影響,或者須要寫複雜的shouldComponentUpdate進行判斷。promise

 

三、react組件的劃分業務組件技術組件?瀏覽器

根據組件的職責一般把組件分爲UI組件和容器組件。緩存

UI 組件負責 UI 的呈現,容器組件負責管理數據和邏輯。安全

二者經過React-Redux 提供connect方法聯繫起來。

具體使用能夠參照以下連接:http://www.ruanyifeng.com/blog/2016/09/redux_tutorial_part_three_react-redux.html

 

四、react生命週期函數

這個問題要考察的是組件的生命週期

1、初始化階段:

getDefaultProps:獲取實例的默認屬性

getInitialState:獲取每一個實例的初始化狀態

componentWillMount:組件即將被裝載、渲染到頁面上

render:組件在這裏生成虛擬的DOM節點

componentDidMount:組件真正在被裝載以後

2、運行中狀態:

componentWillReceiveProps:組件將要接收到屬性的時候調用

shouldComponentUpdate:組件接受到新屬性或者新狀態的時候(能夠返回false,接收數據後不更新,阻止render調用,後面的函數不會被繼續執行了)

componentWillUpdate:組件即將更新不能修改屬性和狀態

render:組件從新描繪

componentDidUpdate:組件已經更新

3、銷燬階段:

componentWillUnmount:組件即將銷燬

 

五、react性能優化是哪一個周期函數?

shouldComponentUpdate 這個方法用來判斷是否須要調用render方法從新描繪dom。由於dom的描繪很是消耗性能,若是咱們能在shouldComponentUpdate方法中可以寫出更優化的dom diff算法,能夠極大的提升性能。

詳細參考:

https//segmentfault.com/a/1190000006254212

 

六、爲何虛擬dom會提升性能?

虛擬dom至關於在js和真實dom中間加了一個緩存,利用dom diff算法避免了沒有必要的dom操做,從而提升性能。

具體實現步驟以下:

用 JavaScript 對象結構表示 DOM 樹的結構;而後用這個樹構建一個真正的 DOM 樹,插到文檔當中

當狀態變動的時候,從新構造一棵新的對象樹。而後用新的樹和舊的樹進行比較,記錄兩棵樹差別

把2所記錄的差別應用到步驟1所構建的真正的DOM樹上,視圖就更新了。

參考連接:

https://www.zhihu.com/question/29504639?sort=created

 

七、diff算法?

把樹形結構按照層級分解,只比較同級元素。

給列表結構的每一個單元添加惟一的key屬性,方便比較。

React 只會匹配相同 class 的 component(這裏面的class指的是組件的名字)

合併操做,調用 component 的 setState 方法的時候, React 將其標記爲 dirty.到每個事件循環結束, React 檢查全部標記 dirty 的 component 從新繪製.

選擇性子樹渲染。開發人員能夠重寫shouldComponentUpdate提升diff的性能。

參考連接:

https//segmentfault.com/a/1190000000606216

八、react性能優化方案

(1)重寫shouldComponentUpdate來避免沒必要要的dom操做。

(2)使用 production 版本的react.js。

(3)使用key來幫助React識別列表中全部子組件的最小變化。

參考連接:

https://segmentfault.com/a/1190000006254212
 

 

九、簡述flux 思想

Flux 的最大特色,就是數據的"單向流動"。

1.用戶訪問 View

2.View 發出用戶的 Action

3.Dispatcher 收到 Action,要求 Store 進行相應的更新

4.Store 更新後,發出一個"change"事件

5.View 收到"change"事件後,更新頁面

參考連接:

http://www.ruanyifeng.com/blog/2016/01/flux.html

十、React項目用過什麼腳手架?Mern? Yeoman?

Mern:MERN是腳手架的工具,它能夠很容易地使用Mongo, Express, React and NodeJS生成同構JS應用。它最大限度地減小安裝時間,並獲得您使用的成熟技術來加速開發。

 

下面的也是喲

調用 setState 以後發生了什麼?

在代碼中調用setState函數以後,React 會將傳入的參數對象與組件當前的狀態合併,而後觸發所謂的調和過程(Reconciliation)。通過調和過程,React 會以相對高效的方式根據新的狀態構建 React 元素樹而且着手從新渲染整個UI界面。在 React 獲得元素樹以後,React 會自動計算出新的樹與老樹的節點差別,而後根據差別對界面進行最小化重渲染。在差別計算算法中,React 可以相對精確地知道哪些位置發生了改變以及應該如何改變,這就保證了按需更新,而不是所有從新渲染。

React 中 Element 與 Component 的區別是?

簡單而言,React Element 是描述屏幕上所見內容的數據結構,是對於 UI 的對象表述。典型的 React Element 就是利用 JSX 構建的聲明式代碼片而後被轉化爲createElement的調用組合。而 React Component 則是能夠接收參數輸入而且返回某個 React Element 的函數或者類。

在什麼狀況下你會優先選擇使用 Class Component 而不是 Functional Component?

在組件須要包含內部狀態或者使用到生命週期函數的時候使用 Class Component ,不然使用函數式組件。

React 中 refs 的做用是什麼?

注意,根據React最新文檔,下面這種用法已經被棄用了,統一改成回調函數模式
this.refs.textInput

Refs 是 React 提供給咱們的安全訪問 DOM 元素或者某個組件實例的句柄。咱們能夠爲元素添加ref屬性而後在回調函數中接受該元素在 DOM 樹中的句柄,該值會做爲回調函數的第一個參數返回:

class CustomForm extends Component {
  handleSubmit = () => {
    console.log("Input Value: ", this.input.value)
  }
  render () {
    return (
      <form onSubmit={this.handleSubmit}>
        <input
          type='text'
          ref={(input) => this.input = input} />
        <button type='submit'>Submit</button>
      </form>
    )
  }
}

上述代碼中的input域包含了一個ref屬性,該屬性聲明的回調函數會接收input對應的 DOM 元素,咱們將其綁定到this指針以便在其餘的類函數中使用。另外值得一提的是,refs 並非類組件的專屬,函數式組件一樣可以利用閉包暫存其值:

function CustomForm ({handleSubmit}) {
  let inputElement
  return (
    <form onSubmit={() => handleSubmit(inputElement.value)}>
      <input
        type='text'
        ref={(input) => inputElement = input} />
      <button type='submit'>Submit</button>
    </form>
  )
}

React 中 keys 的做用是什麼?

Keys 是 React 用於追蹤哪些列表中元素被修改、被添加或者被移除的輔助標識。

render () {
  return (
    <ul>
      {this.state.todoItems.map(({task, uid}) => {
        return <li key={uid}>{task}</li>
      })}
    </ul>
  )
}

在開發過程當中,咱們須要保證某個元素的 key 在其同級元素中具備惟一性。在 React Diff 算法中 React 會藉助元素的 Key 值來判斷該元素是新近建立的仍是被移動而來的元素,從而減小沒必要要的元素重渲染。此外,React 還須要藉助 Key 值來判斷元素與本地狀態的關聯關係,所以咱們毫不可忽視轉換函數中 Key 的重要性。

若是你建立了相似於下面的Twitter元素,那麼它相關的類定義是啥樣子的?

<Twitter username='tylermcginnis33'>
  {(user) => user === null
    ? <Loading />
    : <Badge info={user} />}
</Twitter>
import React, { Component, PropTypes } from 'react'
import fetchUser from 'twitter'
// fetchUser take in a username returns a promise
// which will resolve with that username's data.
class Twitter extends Component {
  // finish this
}

若是你還不熟悉回調渲染模式(Render Callback Pattern),這個代碼可能看起來有點怪。這種模式中,組件會接收某個函數做爲其子組件,而後在渲染函數中以props.children進行調用:

import React, { Component, PropTypes } from 'react'
import fetchUser from 'twitter'
class Twitter extends Component {
  state = {
    user: null,
  }
  static propTypes = {
    username: PropTypes.string.isRequired,
  }
  componentDidMount () {
    fetchUser(this.props.username)
      .then((user) => this.setState({user}))
  }
  render () {
    return this.props.children(this.state.user)
  }
}

這種模式的優點在於將父組件與子組件解耦和,父組件能夠直接訪問子組件的內部狀態而不須要再經過Props傳遞,這樣父組件可以更爲方便地控制子組件展現的UI界面。譬如產品經理讓咱們將本來展現的Badge替換爲Profile,咱們能夠輕易地修改下回調函數便可:

<Twitter username='tylermcginnis33'>
  {(user) => user === null
    ? <Loading />
    : <Profile info={user} />}
</Twitter>

Controlled Component 與 Uncontrolled Component 之間的區別是什麼?

React 的核心組成之一就是可以維持內部狀態的自治組件,不過當咱們引入原生的HTML表單元素時(input,select,textarea 等),咱們是否應該將全部的數據託管到 React 組件中仍是將其仍然保留在 DOM 元素中呢?這個問題的答案就是受控組件與非受控組件的定義分割。受控組件(Controlled Component)代指那些交由 React 控制而且全部的表單數據統一存放的組件。譬以下面這段代碼中username變量值並無存放到DOM元素中,而是存放在組件狀態數據中。任什麼時候候咱們須要改變username變量值時,咱們應當調用setState函數進行修改。

class ControlledForm extends Component {
  state = {
    username: ''
  }
  updateUsername = (e) => {
    this.setState({
      username: e.target.value,
    })
  }
  handleSubmit = () => {}
  render () {
    return (
      <form onSubmit={this.handleSubmit}>
        <input
          type='text'
          value={this.state.username}
          onChange={this.updateUsername} />
        <button type='submit'>Submit</button>
      </form>
    )
  }
}

而非受控組件(Uncontrolled Component)則是由DOM存放表單數據,並不是存放在 React 組件中。咱們可使用 refs 來操控DOM元素:

class UnControlledForm extends Component {
  handleSubmit = () => {
    console.log("Input Value: ", this.input.value)
  }
  render () {
    return (
      <form onSubmit={this.handleSubmit}>
        <input
          type='text'
          ref={(input) => this.input = input} />
        <button type='submit'>Submit</button>
      </form>
    )
  }
}

居然非受控組件看上去更好實現,咱們能夠直接從 DOM 中抓取數據,而不須要添加額外的代碼。不過實際開發中咱們並不提倡使用非受控組件,由於實際狀況下咱們須要更多的考慮表單驗證、選擇性的開啓或者關閉按鈕點擊、強制輸入格式等功能支持,而此時咱們將數據託管到 React 中有助於咱們更好地以聲明式的方式完成這些功能。引入 React 或者其餘 MVVM 框架最初的緣由就是爲了將咱們從繁重的直接操做 DOM 中解放出來。

在生命週期中的哪一步你應該發起 AJAX 請求?

咱們應當將AJAX 請求放到 componentDidMount 函數中執行,主要緣由有下:

  • React 下一代調和算法 Fiber 會經過開始或中止渲染的方式優化應用性能,其會影響到 componentWillMount 的觸發次數。對於 componentWillMount 這個生命週期函數的調用次數會變得不肯定,React 可能會屢次頻繁調用 componentWillMount。若是咱們將 AJAX 請求放到 componentWillMount 函數中,那麼顯而易見其會被觸發屢次,天然也就不是好的選擇。

  • 若是咱們將 AJAX 請求放置在生命週期的其餘函數中,咱們並不能保證請求僅在組件掛載完畢後纔會要求響應。若是咱們的數據請求在組件掛載以前就完成,而且調用了setState函數將數據添加到組件狀態中,對於未掛載的組件則會報錯。而在 componentDidMount 函數中進行 AJAX 請求則能有效避免這個問題。

shouldComponentUpdate 的做用是啥以及爲什麼它這麼重要?

shouldComponentUpdate 容許咱們手動地判斷是否要進行組件更新,根據組件的應用場景設置函數的合理返回值可以幫咱們避免沒必要要的更新。

如何告訴 React 它應該編譯生產環境版本?

一般狀況下咱們會使用 Webpack 的 DefinePlugin 方法來將 NODE_ENV 變量值設置爲 production。編譯版本中 React 會忽略 propType 驗證以及其餘的告警信息,同時還會下降代碼庫的大小,React 使用了 Uglify 插件來移除生產環境下沒必要要的註釋等信息。

爲何咱們須要使用 React 提供的 Children API 而不是 JavaScript 的 map?

React.Children.map(props.children, () => )  instead of props.children.map(() => )

props.children並不必定是數組類型,譬以下面這個元素:

<Parent>
  <h1>Welcome.</h1>
</Parent>

若是咱們使用props.children.map函數來遍歷時會受到異常提示,由於在這種狀況下props.children是對象(object)而不是數組(array)。React 當且僅當超過一個子元素的狀況下會將props.children設置爲數組,就像下面這個代碼片:

<Parent>
  <h1>Welcome.</h1>
  <h2>props.children will now be an array</h2>
</Parent>

這也就是咱們優先選擇使用React.Children.map函數的緣由,其已經將props.children不一樣類型的狀況考慮在內了。

概述下 React 中的事件處理邏輯

爲了解決跨瀏覽器兼容性問題,React 會將瀏覽器原生事件(Browser Native Event)封裝爲合成事件(SyntheticEvent)傳入設置的事件處理器中。這裏的合成事件提供了與原生事件相同的接口,不過它們屏蔽了底層瀏覽器的細節差別,保證了行爲的一致性。另外有意思的是,React 並無直接將事件附着到子元素上,而是以單一事件監聽器的方式將全部的事件發送到頂層進行處理。這樣 React 在更新 DOM 的時候就不須要考慮如何去處理附着在 DOM 上的事件監聽器,最終達到優化性能的目的。

createElement 與 cloneElement 的區別是什麼?

createElement 函數是 JSX 編譯以後使用的建立 React Element 的函數,而 cloneElement 則是用於複製某個元素並傳入新的 Props。

傳入 setState 函數的第二個參數的做用是什麼?

該函數會在setState函數調用完成而且組件開始重渲染的時候被調用,咱們能夠用該函數來監聽渲染是否完成:

this.setState(
  { username: 'tylermcginnis33' },
  () => console.log('setState has finished and the component has re-rendered.')
)

下述代碼有錯嗎?

this.setState((prevState, props) => {
  return {
    streak: prevState.streak + props.count
  }
})
相關文章
相關標籤/搜索