React 中 keys 的作用是什么?
Keys 是 React 用于追蹤哪些列表中元素被修改、被添加或者被移除的輔助標識。
render () {return(? ?
- ? ? ? {this.state.todoItems.map(({item, key}) => {return
- {item} ? ? ? })}? ?
在開發(fā)過程中,我們需要保證某個元素的 key 在其同級元素中具有唯一性。在 React Diff 算法中 React 會借助元素的 Key 值來判斷該元素是新近創(chuàng)建的還是被移動而來的元素削罩,從而減少不必要的元素重渲染。此外趾疚,React 還需要借助 Key 值來判斷元素與本地狀態(tài)的關聯(lián)關系赡磅,因此我們絕不可忽視轉換函數(shù)中 Key 的重要性冶匹。
調用 setState 之后發(fā)生了什么飞蛹?
在代碼中調用 setState 函數(shù)之后幢炸,React 會將傳入的參數(shù)對象與組件當前的狀態(tài)合并,然后觸發(fā)所謂的調和過程(Reconciliation)。經過調和過程,React 會以相對高效的方式根據(jù)新的狀態(tài)構建 React 元素樹并且著手重新渲染整個 UI 界面。在 React 得到元素樹之后,React 會自動計算出新的樹與老樹的節(jié)點差異,然后根據(jù)差異對界面進行最小化重渲染。在差異計算算法中,React 能夠相對精確地知道哪些位置發(fā)生了改變以及應該如何改變辈毯,這就保證了按需更新唁影,而不是全部重新渲染。
react 生命周期函數(shù)
初始化階段:
getDefaultProps:獲取實例的默認屬性
getInitialState:獲取每個實例的初始化狀態(tài)
componentWillMount:組件即將被裝載猾警、渲染到頁面上
render:組件在這里生成虛擬的 DOM 節(jié)點
componentDidMount:組件真正在被裝載之后
運行中狀態(tài):
componentWillReceiveProps:組件將要接收到屬性的時候調用
shouldComponentUpdate:組件接受到新屬性或者新狀態(tài)的時候(可以返回 false穴墅,接收數(shù)據(jù)后不更新,阻止 render 調用券躁,后面的函數(shù)不會被繼續(xù)執(zhí)行了)
componentWillUpdate:組件即將更新不能修改屬性和狀態(tài)
render:組件重新描繪
componentDidUpdate:組件已經更新
銷毀階段:
componentWillUnmount:組件即將銷毀
shouldComponentUpdate 是做什么的慢哈,(react 性能優(yōu)化是哪個周期函數(shù)滥沫?)
shouldComponentUpdate 這個方法用來判斷是否需要調用 render 方法重新描繪 dom世分。因為 dom 的描繪非常消耗性能,如果我們能在 shouldComponentUpdate 方法中能夠寫出更優(yōu)化的 dom diff 算法,可以極大的提高性能。
為什么虛擬 dom 會提高性能?(必考)
虛擬 dom 相當于在 js 和真實 dom 中間加了一個緩存,利用 dom diff 算法避免了沒有必要的 dom 操作痹束,從而提高性能。
用 JavaScript 對象結構表示 DOM 樹的結構;然后用這個樹構建一個真正的 DOM 樹嘉汰,插到文檔當中當狀態(tài)變更的時候,重新構造一棵新的對象樹。然后用新的樹和舊的樹進行比較,記錄兩棵樹差異把 2 所記錄的差異應用到步驟 1 所構建的真正的 DOM 樹上抛猫,視圖就更新了掖看。
react diff 原理(骋愦考,大廠必考)
把樹形結構按照層級分解悯森,只比較同級元素墩莫。
給列表結構的每個單元添加唯一的 key 屬性推捐,方便比較。
React 只會匹配相同 class 的 component(這里面的 class 指的是組件的名字)
合并操作符喝,調用 component 的 setState 方法的時候, React 將其標記為 dirty.到每一個事件循環(huán)結束, React 檢查所有標記 dirty 的 component 重新繪制.
選擇性子樹渲染缴川。開發(fā)人員可以重寫 shouldComponentUpdate 提高 diff 的性能铭污。
React 中 refs 的作用是什么?
Refs 是 React 提供給我們的安全訪問 DOM 元素或者某個組件實例的句柄嘹狞。我們可以為元素添加 ref 屬性然后在回調函數(shù)中接受該元素在 DOM 樹中的句柄岂膳,該值會作為回調函數(shù)的第一個參數(shù)返回:
classCustomFormextendsComponent{? handleSubmit = () => {? ? console.log("Input Value: ",this.input.value)? }? render () {return(? ? ? ? ? ? ? this.input = input} />? ? ? ? Submit? ? ? ? ? )? }}
上述代碼中的 input 域包含了一個 ref 屬性,該屬性聲明的回調函數(shù)會接收 input 對應的 DOM 元素磅网,我們將其綁定到 this 指針以便在其他的類函數(shù)中使用谈截。另外值得一提的是,refs 并不是類組件的專屬涧偷,函數(shù)式組件同樣能夠利用閉包暫存其值:
functionCustomForm({handleSubmit}){letinputElementreturn(handleSubmit(inputElement.value)}>inputElement = input} />Submit)}
如果你創(chuàng)建了類似于下面的 Twitter 元素簸喂,那么它相關的類定義是啥樣子的?
{(user) => user === null? ? ?:}
importReact, {Component,PropTypes} from'react'importfetchUser from'twitter'// fetchUser take in a username returns a promise// which will resolve with that username's data.classTwitterextendsComponent{// finish this}
如果你還不熟悉回調渲染模式(Render Callback Pattern)燎潮,這個代碼可能看起來有點怪喻鳄。這種模式中,組件會接收某個函數(shù)作為其子組件跟啤,然后在渲染函數(shù)中以 props.children 進行調用:
importReact, {Component,PropTypes} from'react'importfetchUser from'twitter'classTwitterextendsComponent{? state = {? ? user:null,? }? static propTypes = {? ? username:PropTypes.string.isRequired,? }? componentDidMount () {? ? fetchUser(this.props.username)? ? ? .then((user) =>this.setState({user}))? }? render () {returnthis.props.children(this.state.user)? }}
這種模式的優(yōu)勢在于將父組件與子組件解耦和诽表,父組件可以直接訪問子組件的內部狀態(tài)而不需要再通過 Props 傳遞,這樣父組件能夠更為方便地控制子組件展示的 UI 界面隅肥。譬如產品經理讓我們將原本展示的 Badge 替換為 Profile竿奏,我們可以輕易地修改下回調函數(shù)即可:
{(user) => user === null? ? ?:}
展示組件(Presentational component)和容器組件(Container component)之間有何不同
展示組件關心組件看起來是什么。展示專門通過 props 接受數(shù)據(jù)和回調腥放,并且?guī)缀醪粫凶陨淼臓顟B(tài)泛啸,但當展示組件擁有自身的狀態(tài)時,通常也只關心 UI 狀態(tài)而不是數(shù)據(jù)的狀態(tài)秃症。
容器組件則更關心組件是如何運作的候址。容器組件會為展示組件或者其它容器組件提供數(shù)據(jù)和行為(behavior),它們會調用 Flux actions种柑,并將其作為回調提供給展示組件岗仑。容器組件經常是有狀態(tài)的,因為它們是(其它組件的)數(shù)據(jù)源聚请。
類組件(Class component)和函數(shù)式組件(Functional component)之間有何不同
類組件不僅允許你使用更多額外的功能荠雕,如組件自身的狀態(tài)和生命周期鉤子稳其,也能使組件直接訪問 store 并維持狀態(tài)
當組件僅是接收 props,并將組件自身渲染到頁面時炸卑,該組件就是一個 '無狀態(tài)組件(stateless component)'既鞠,可以使用一個純函數(shù)來創(chuàng)建這樣的組件。這種組件也被稱為啞組件(dumb components)或展示組件
(組件的)狀態(tài)(state)和屬性(props)之間有何不同
State 是一種數(shù)據(jù)結構盖文,用于組件掛載時所需數(shù)據(jù)的默認值嘱蛋。State 可能會隨著時間的推移而發(fā)生突變,但多數(shù)時候是作為用戶事件行為的結果五续。
Props(properties 的簡寫)則是組件的配置洒敏。props 由父組件傳遞給子組件,并且就子組件而言返帕,props 是不可變的(immutable)桐玻。組件不能改變自身的 props,但是可以把其子組件的 props 放在一起(統(tǒng)一管理)荆萤。Props 也不僅僅是數(shù)據(jù)--回調函數(shù)也可以通過 props 傳遞镊靴。
何為受控組件(controlled component)
在 HTML 中,類似?<input>,?<textarea>?和?<select>?這樣的表單元素會維護自身的狀態(tài)链韭,并基于用戶的輸入來更新偏竟。當用戶提交表單時,前面提到的元素的值將隨表單一起被發(fā)送敞峭。但在 React 中會有些不同踊谋,包含表單元素的組件將會在 state 中追蹤輸入的值,并且每次調用回調函數(shù)時旋讹,如 onChange 會更新 state殖蚕,重新渲染組件。一個輸入表單元素沉迹,它的值通過 React 的這種方式來控制睦疫,這樣的元素就被稱為"受控元素"。
何為高階組件(higher order component)
高階組件是一個以組件為參數(shù)并返回一個新組件的函數(shù)鞭呕。HOC 運行你重用代碼蛤育、邏輯和引導抽象。最常見的可能是 Redux 的 connect 函數(shù)葫松。除了簡單分享工具庫和簡單的組合瓦糕,HOC 最好的方式是共享 React 組件之間的行為。如果你發(fā)現(xiàn)你在不同的地方寫了大量代碼來做同一件事時腋么,就應該考慮將代碼重構為可重用的 HOC咕娄。
為什么建議傳遞給 setState 的參數(shù)是一個 callback 而不是一個對象
因為 this.props 和 this.state 的更新可能是異步的,不能依賴它們的值去計算下一個 state珊擂。
除了在構造函數(shù)中綁定 this圣勒,還有其它方式嗎
你可以使用屬性初始值設定項(property initializers)來正確綁定回調徐块,create-react-app 也是默認支持的。在回調中你可以使用箭頭函數(shù)灾而,但問題是每次組件渲染時都會創(chuàng)建一個新的回調。
(在構造函數(shù)中)調用 super(props) 的目的是什么
在 super() 被調用之前扳剿,子類是不能使用 this 的旁趟,在 ES2015 中,子類必須在 constructor 中調用 super()庇绽。傳遞 props 給 super() 的原因則是便于(在子類中)能在 constructor 訪問 this.props锡搜。
應該在 React 組件的何處發(fā)起 Ajax 請求
在 React 組件中,應該在 componentDidMount 中發(fā)起網(wǎng)絡請求瞧掺。這個方法會在組件第一次“掛載”(被添加到 DOM)時執(zhí)行耕餐,在組件的生命周期中僅會執(zhí)行一次。更重要的是辟狈,你不能保證在組件掛載之前 Ajax 請求已經完成肠缔,如果是這樣,也就意味著你將嘗試在一個未掛載的組件上調用 setState哼转,這將不起作用明未。在 componentDidMount 中發(fā)起網(wǎng)絡請求將保證這有一個組件可以更新了。
描述事件在 React 中的處理方式壹蔓。
為了解決跨瀏覽器兼容性問題趟妥,您的 React 中的事件處理程序將傳遞 SyntheticEvent 的實例,它是 React 的瀏覽器本機事件的跨瀏覽器包裝器佣蓉。
這些 SyntheticEvent 與您習慣的原生事件具有相同的接口披摄,除了它們在所有瀏覽器中都兼容。有趣的是勇凭,React 實際上并沒有將事件附加到子節(jié)點本身疚膊。React 將使用單個事件監(jiān)聽器監(jiān)聽頂層的所有事件。這對于性能是有好處的套像,這也意味著在更新 DOM 時酿联,React 不需要擔心跟蹤事件監(jiān)聽器。
createElement 和 cloneElement 有什么區(qū)別夺巩?
React.createElement():JSX 語法就是用 React.createElement()來構建 React 元素的贞让。它接受三個參數(shù),第一個參數(shù)可以是一個標簽名柳譬。如 div喳张、span,或者 React 組件美澳。第二個參數(shù)為傳入的屬性销部。第三個以及之后的參數(shù)摸航,皆作為組件的子組件。
React.createElement(type,[props],[...children])
React.cloneElement()與 React.createElement()相似舅桩,不同的是它傳入的第一個參數(shù)是一個 React 元素酱虎,而不是標簽名或組件。新添加的屬性會并入原有的屬性擂涛,傳入到返回的新元素中读串,而就的子元素獎杯替換。
React.cloneElement(element,[props],[...children])
React 中有三種構建組件的方式
React.createClass()撒妈、ES6 class 和無狀態(tài)函數(shù)恢暖。
react 組件的劃分業(yè)務組件技術組件?
根據(jù)組件的職責通常把組件分為 UI 組件和容器組件狰右。
UI 組件負責 UI 的呈現(xiàn)杰捂,容器組件負責管理數(shù)據(jù)和邏輯。
兩者通過 React-Redux 提供 connect 方法聯(lián)系起來棋蚌。
簡述 flux 思想
Flux 的最大特點嫁佳,就是數(shù)據(jù)的"單向流動"。
用戶訪問 View
View 發(fā)出用戶的 Action
Dispatcher 收到 Action谷暮,要求 Store 進行相應的更新
Store 更新后脱拼,發(fā)出一個"change"事件
View 收到"change"事件后,更新頁面
了解 redux 么坷备,說一下 redux 把
redux 是一個應用數(shù)據(jù)流框架熄浓,主要是解決了組件間狀態(tài)共享的問題,原理是集中式管理省撑,主要有三個核心方法赌蔑,action,store竟秫,reducer娃惯,工作流程是 view 調用 store 的 dispatch 接收 action 傳入 store,reducer 進行 state 操作肥败,view 通過 store 提供的 getState 獲取最新的數(shù)據(jù)趾浅,flux 也是用來進行數(shù)據(jù)操作的,有四個組成部分 action馒稍,dispatch皿哨,view,store纽谒,工作流程是 view 發(fā)出一個 action证膨,派發(fā)器接收 action,讓 store 進行數(shù)據(jù)更新鼓黔,更新完成以后 store 發(fā)出 change央勒,view 接受 change 更新視圖不见。Redux 和 Flux 很像。主要區(qū)別在于 Flux 有多個可以改變應用狀態(tài)的 store崔步,在 Flux 中 dispatcher 被用來傳遞數(shù)據(jù)到注冊的回調事件稳吮,但是在 redux 中只能定義一個可更新狀態(tài)的 store,redux 把 store 和 Dispatcher 合并,結構更加簡單清晰
新增 state,對狀態(tài)的管理更加明確井濒,通過 redux盖高,流程更加規(guī)范了,減少手動編碼量眼虱,提高了編碼效率,同時缺點時當數(shù)據(jù)更新時有時候組件不需要席纽,但是也要重新繪制捏悬,有些影響效率。一般情況下润梯,我們在構建多交互过牙,多數(shù)據(jù)流的復雜項目應用時才會使用它們
redux 有什么缺點
一個組件所需要的數(shù)據(jù),必須由父組件傳過來纺铭,而不能像 flux 中直接從 store 取寇钉。
當一個組件相關數(shù)據(jù)更新時,即使父組件不需要用到這個組件舶赔,父組件還是會重新 render扫倡,可能會有效率影響,或者需要寫復雜的 shouldComponentUpdate 進行判斷竟纳。