常見的中間件:
redux-logger:提供日志輸出
redux-thunk:處理異步操作
redux-promise:處理異步操作,actionCreator的返回值是promise
2、redux有什么缺點
1.一個組件所需要的數據,必須由父組件傳過來,而不能像flux中直接從store取。
2.當一個組件相關數據更新時,即使父組件不需要用到這個組件,父組件還是會重新render,可能會有效率影響,或者需要寫復雜的shouldComponentUpdate進行判斷。
3、react組件的划分業務組件技術組件?
根據組件的職責通常把組件分為UI組件和容器組件。
UI 組件負責 UI 的呈現,容器組件負責管理數據和邏輯。
兩者通過React-Redux 提供connect方法聯系起來。
具體使用可以參照如下鏈接:http://www.ruanyifeng.com/blog/2016/09/redux_tutorial_part_three_react-redux.html
4、react生命周期函數
這個問題要考察的是組件的生命周期
一、初始化階段:
getDefaultProps:獲取實例的默認屬性
getInitialState:獲取每個實例的初始化狀態
componentWillMount:組件即將被裝載、渲染到頁面上
render:組件在這里生成虛擬的DOM節點
componentDidMount:組件真正在被裝載之后
二、運行中狀態:
componentWillReceiveProps:組件將要接收到屬性的時候調用
shouldComponentUpdate:組件接受到新屬性或者新狀態的時候(可以返回false,接收數據后不更新,阻止render調用,后面的函數不會被繼續執行了)
componentWillUpdate:組件即將更新不能修改屬性和狀態
render:組件重新描繪
componentDidUpdate:組件已經更新
三、銷毀階段:
componentWillUnmount:組件即將銷毀
5、react性能優化是哪個周期函數?
shouldComponentUpdate 這個方法用來判斷是否需要調用render方法重新描繪dom。因為dom的描繪非常消耗性能,如果我們能在shouldComponentUpdate方法中能夠寫出更優化的dom diff算法,可以極大的提高性能。
詳細參考:
https//segmentfault.com/a/1190000006254212
6、為什么虛擬dom會提高性能?
虛擬dom相當於在js和真實dom中間加了一個緩存,利用dom diff算法避免了沒有必要的dom操作,從而提高性能。
具體實現步驟如下:
用 JavaScript 對象結構表示 DOM 樹的結構;然后用這個樹構建一個真正的 DOM 樹,插到文檔當中
當狀態變更的時候,重新構造一棵新的對象樹。然后用新的樹和舊的樹進行比較,記錄兩棵樹差異
把2所記錄的差異應用到步驟1所構建的真正的DOM樹上,視圖就更新了。
參考鏈接:
https://www.zhihu.com/question/29504639?sort=created
7、diff算法?
把樹形結構按照層級分解,只比較同級元素。
給列表結構的每個單元添加唯一的key屬性,方便比較。
React 只會匹配相同 class 的 component(這里面的class指的是組件的名字)
合並操作,調用 component 的 setState 方法的時候, React 將其標記為 dirty.到每一個事件循環結束, React 檢查所有標記 dirty 的 component 重新繪制.
選擇性子樹渲染。開發人員可以重寫shouldComponentUpdate提高diff的性能。
參考鏈接:
https//segmentfault.com/a/1190000000606216
8、react性能優化方案
(1)重寫shouldComponentUpdate來避免不必要的dom操作。
(2)使用 production 版本的react.js。
(3)使用key來幫助React識別列表中所有子組件的最小變化。
參考鏈接:
https://segmentfault.com/a/1190000006254212
9、簡述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
10、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
}
})