React 中 keys 的做用是什麼?react
Keys 是 React 用於追蹤哪些列表中元素被修改、被添加或者被移除的輔助標識。git
render () {
return (
<ul>
{this.state.todoItems.map(({item, key}) => {
return <li key={key}>{item}</li>
})}
</ul>
)
}github
在開發過程當中,咱們須要保證某個元素的 key 在其同級元素中具備惟一性。在 React Diff 算法中 React 會藉助元素的 Key 值來判斷該元素是新近建立的仍是被移動而來的元素,從而減小沒必要要的元素重渲染。此外,React 還須要藉助 Key 值來判斷元素與本地狀態的關聯關係,所以咱們毫不可忽視轉換函數中 Key 的重要性。算法
調用 setState 以後發生了什麼?redux
在代碼中調用 setState 函數以後,React 會將傳入的參數對象與組件當前的狀態合併,而後觸發所謂的調和過程(Reconciliation)。通過調和過程,React 會以相對高效的方式根據新的狀態構建 React 元素樹而且着手從新渲染整個 UI 界面。在 React 獲得元素樹以後,React 會自動計算出新的樹與老樹的節點差別,而後根據差別對界面進行最小化重渲染。在差別計算算法中,React 可以相對精確地知道哪些位置發生了改變以及應該如何改變,這就保證了按需更新,而不是所有從新渲染。promise
react 生命週期函數瀏覽器
初始化階段:緩存
getDefaultProps:獲取實例的默認屬性安全
getInitialState:獲取每一個實例的初始化狀態性能優化
componentWillMount:組件即將被裝載、渲染到頁面上
render:組件在這裏生成虛擬的 DOM 節點
componentDidMount:組件真正在被裝載以後
運行中狀態:
componentWillReceiveProps:組件將要接收到屬性的時候調用
shouldComponentUpdate:組件接受到新屬性或者新狀態的時候(能夠返回 false,接收數據後不更新,阻止 render 調用,後面的函數不會被繼續執行了)
componentWillUpdate:組件即將更新不能修改屬性和狀態
render:組件從新描繪
componentDidUpdate:組件已經更新
銷燬階段:
componentWillUnmount:組件即將銷燬
shouldComponentUpdate 是作什麼的,(react 性能優化是哪一個周期函數?)
shouldComponentUpdate 這個方法用來判斷是否須要調用 render 方法從新描繪 dom。由於 dom 的描繪很是消耗性能,若是咱們能在 shouldComponentUpdate 方法中可以寫出更優化的 dom diff 算法,能夠極大的提升性能。
參考react 性能優化-sf
爲何虛擬 dom 會提升性能?(必考)
虛擬 dom 至關於在 js 和真實 dom 中間加了一個緩存,利用 dom diff 算法避免了沒有必要的 dom 操做,從而提升性能。
用 JavaScript 對象結構表示 DOM 樹的結構;而後用這個樹構建一個真正的 DOM 樹,插到文檔當中當狀態變動的時候,從新構造一棵新的對象樹。而後用新的樹和舊的樹進行比較,記錄兩棵樹差別把 2 所記錄的差別應用到步驟 1 所構建的真正的 DOM 樹上,視圖就更新了。
參考 如何理解虛擬 DOM?-zhihu
react diff 原理(常考,大廠必考)
把樹形結構按照層級分解,只比較同級元素。
給列表結構的每一個單元添加惟一的 key 屬性,方便比較。
React 只會匹配相同 class 的 component(這裏面的 class 指的是組件的名字)
合併操做,調用 component 的 setState 方法的時候, React 將其標記爲 dirty.到每個事件循環結束, React 檢查全部標記 dirty 的 component 從新繪製.
選擇性子樹渲染。開發人員能夠重寫 shouldComponentUpdate 提升 diff 的性能。
參考:React 的 diff 算法
React 中 refs 的做用是什麼?
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>
)
}
若是你建立了相似於下面的 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>
展現組件(Presentational component)和容器組件(Container component)之間有何不一樣
展現組件關心組件看起來是什麼。展現專門經過 props 接受數據和回調,而且幾乎不會有自身的狀態,但當展現組件擁有自身的狀態時,一般也只關心 UI 狀態而不是數據的狀態。
容器組件則更關心組件是如何運做的。容器組件會爲展現組件或者其它容器組件提供數據和行爲(behavior),它們會調用 Flux actions,並將其做爲回調提供給展現組件。容器組件常常是有狀態的,由於它們是(其它組件的)數據源。
類組件(Class component)和函數式組件(Functional component)之間有何不一樣
類組件不只容許你使用更多額外的功能,如組件自身的狀態和生命週期鉤子,也能使組件直接訪問 store 並維持狀態
當組件僅是接收 props,並將組件自身渲染到頁面時,該組件就是一個 '無狀態組件(stateless component)',可使用一個純函數來建立這樣的組件。這種組件也被稱爲啞組件(dumb components)或展現組件
(組件的)狀態(state)和屬性(props)之間有何不一樣
State 是一種數據結構,用於組件掛載時所需數據的默認值。State 可能會隨着時間的推移而發生突變,但多數時候是做爲用戶事件行爲的結果。
Props(properties 的簡寫)則是組件的配置。props 由父組件傳遞給子組件,而且就子組件而言,props 是不可變的(immutable)。組件不能改變自身的 props,可是能夠把其子組件的 props 放在一塊兒(統一管理)。Props 也不只僅是數據--回調函數也能夠經過 props 傳遞。
何爲受控組件(controlled component)
在 HTML 中,相似 <input>, <textarea> 和 <select> 這樣的表單元素會維護自身的狀態,並基於用戶的輸入來更新。當用戶提交表單時,前面提到的元素的值將隨表單一塊兒被髮送。但在 React 中會有些不一樣,包含表單元素的組件將會在 state 中追蹤輸入的值,而且每次調用回調函數時,如 onChange 會更新 state,從新渲染組件。一個輸入表單元素,它的值經過 React 的這種方式來控制,這樣的元素就被稱爲"受控元素"。
何爲高階組件(higher order component)
高階組件是一個以組件爲參數並返回一個新組件的函數。HOC 運行你重用代碼、邏輯和引導抽象。最多見的多是 Redux 的 connect 函數。除了簡單分享工具庫和簡單的組合,HOC 最好的方式是共享 React 組件之間的行爲。若是你發現你在不一樣的地方寫了大量代碼來作同一件事時,就應該考慮將代碼重構爲可重用的 HOC。
爲何建議傳遞給 setState 的參數是一個 callback 而不是一個對象
由於 this.props 和 this.state 的更新多是異步的,不能依賴它們的值去計算下一個 state。
除了在構造函數中綁定 this,還有其它方式嗎
你可使用屬性初始值設定項(property initializers)來正確綁定回調,create-react-app 也是默認支持的。在回調中你可使用箭頭函數,但問題是每次組件渲染時都會建立一個新的回調。
(在構造函數中)調用 super(props) 的目的是什麼
在 super() 被調用以前,子類是不能使用 this 的,在 ES2015 中,子類必須在 constructor 中調用 super()。傳遞 props 給 super() 的緣由則是便於(在子類中)能在 constructor 訪問 this.props。
應該在 React 組件的何處發起 Ajax 請求
在 React 組件中,應該在 componentDidMount 中發起網絡請求。這個方法會在組件第一次「掛載」(被添加到 DOM)時執行,在組件的生命週期中僅會執行一次。更重要的是,你不能保證在組件掛載以前 Ajax 請求已經完成,若是是這樣,也就意味着你將嘗試在一個未掛載的組件上調用 setState,這將不起做用。在 componentDidMount 中發起網絡請求將保證這有一個組件能夠更新了。
描述事件在 React 中的處理方式。
爲了解決跨瀏覽器兼容性問題,您的 React 中的事件處理程序將傳遞 SyntheticEvent 的實例,它是 React 的瀏覽器本機事件的跨瀏覽器包裝器。
這些 SyntheticEvent 與您習慣的原生事件具備相同的接口,除了它們在全部瀏覽器中都兼容。有趣的是,React 實際上並無將事件附加到子節點自己。React 將使用單個事件監聽器監聽頂層的全部事件。這對於性能是有好處的,這也意味着在更新 DOM 時,React 不須要擔憂跟蹤事件監聽器。
createElement 和 cloneElement 有什麼區別?
React.createElement():JSX 語法就是用 React.createElement()來構建 React 元素的。它接受三個參數,第一個參數能夠是一個標籤名。如 div、span,或者 React 組件。第二個參數爲傳入的屬性。第三個以及以後的參數,皆做爲組件的子組件。
React.createElement(
type,
[props],
[...children]
)
React.cloneElement()與 React.createElement()類似,不一樣的是它傳入的第一個參數是一個 React 元素,而不是標籤名或組件。新添加的屬性會併入原有的屬性,傳入到返回的新元素中,而就的子元素獎盃替換。
React.cloneElement(
element,
[props],
[...children]
)
React 中有三種構建組件的方式
React.createClass()、ES6 class 和無狀態函數。
react 組件的劃分業務組件技術組件?
根據組件的職責一般把組件分爲 UI 組件和容器組件。
UI 組件負責 UI 的呈現,容器組件負責管理數據和邏輯。
二者經過 React-Redux 提供 connect 方法聯繫起來。
簡述 flux 思想
Flux 的最大特色,就是數據的"單向流動"。
用戶訪問 View
View 發出用戶的 Action
Dispatcher 收到 Action,要求 Store 進行相應的更新
Store 更新後,發出一個"change"事件
View 收到"change"事件後,更新頁面
React 項目用過什麼腳手架(本題是開放性題目)
creat-react-app Yeoman 等
瞭解 redux 麼,說一下 redux 把
redux 是一個應用數據流框架,主要是解決了組件間狀態共享的問題,原理是集中式管理,主要有三個核心方法,action,store,reducer,工做流程是 view 調用 store 的 dispatch 接收 action 傳入 store,reducer 進行 state 操做,view 經過 store 提供的 getState 獲取最新的數據,flux 也是用來進行數據操做的,有四個組成部分 action,dispatch,view,store,工做流程是 view 發出一個 action,派發器接收 action,讓 store 進行數據更新,更新完成之後 store 發出 change,view 接受 change 更新視圖。Redux 和 Flux 很像。主要區別在於 Flux 有多個能夠改變應用狀態的 store,在 Flux 中 dispatcher 被用來傳遞數據到註冊的回調事件,可是在 redux 中只能定義一個可更新狀態的 store,redux 把 store 和 Dispatcher 合併,結構更加簡單清晰
新增 state,對狀態的管理更加明確,經過 redux,流程更加規範了,減小手動編碼量,提升了編碼效率,同時缺點時當數據更新時有時候組件不須要,可是也要從新繪製,有些影響效率。通常狀況下,咱們在構建多交互,多數據流的複雜項目應用時纔會使用它們
redux 有什麼缺點
一個組件所須要的數據,必須由父組件傳過來,而不能像 flux 中直接從 store 取。
當一個組件相關數據更新時,即便父組件不須要用到這個組件,父組件仍是會從新 render,可能會有效率影響,或者須要寫複雜的 shouldComponentUpdate 進行判斷。
做者:小胡
原文:https://github.com/nanhupatar/FEGuide/blob/master/框架/react.md