React高頻面試題梳理宇驾,看看面試怎么答猴伶?(上)

前段時(shí)間準(zhǔn)備面試塌西,總結(jié)了很多,下面是我在準(zhǔn)備React面試時(shí)筝尾,結(jié)合自己的實(shí)際面試經(jīng)歷,以及我以前源碼分析的文章站辉,總結(jié)出來的一些React高頻面試題目损姜。

以前我寫的源碼分析的文章摧阅,并沒有很多人看,因?yàn)榇蟛糠智闆r下你不需要深入源碼也能懂得其中原理棒卷,并解決實(shí)際問題比规,這也是我總結(jié)這些面試題的原因苞俘,讓你在更短的時(shí)間內(nèi)獲得更大的收益。

由于是以面試題的角度來討論乞封,所以某些點(diǎn)可能不能非常深入岗憋,我在問題下面都貼了相關(guān)鏈接仔戈,如果想深入理解监徘,請(qǐng)點(diǎn)擊這些文章。

由于題目較多墓卦,分為上户敬、下兩篇,本篇文章我們先來討論如下19個(gè)題目:

React生命周期有哪些呢堰,16版本生命周期發(fā)生了哪些變化凡泣?

setState是同步的還是異步的鞋拟?

為什么有時(shí)連續(xù)多次setState只有一次生效?

React如何實(shí)現(xiàn)自己的事件機(jī)制?

為何React事件要自己綁定this哮笆?

原生事件和React事件的區(qū)別汰扭?

React的合成事件是什么萝毛?

React和原生事件的執(zhí)行順序是什么?可以混用嗎环揽?

虛擬Dom是什么歉胶?

虛擬Dom比普通Dom更快嗎巴粪?

虛擬Dom中的$$typeof屬性的作用是什么肛根?

React組件的渲染流程是什么?

為什么代碼中一定要引入React臼氨?

為什么React組件首字母必須大寫一也?

React在渲染真實(shí)Dom時(shí)做了哪些性能優(yōu)化?

什么是高階組件抑月?如何實(shí)現(xiàn)谦絮?

HOC在業(yè)務(wù)場景中有哪些實(shí)際應(yīng)用場景层皱?

高階組件(HOC)和Mixin的異同點(diǎn)是什么赠潦?

Hook有哪些優(yōu)勢她奥?

React生命周期有哪些,16版本生命周期發(fā)生了哪些變化绷跑?

15生命周期

初始化階段

constructor構(gòu)造函數(shù)

getDefaultPropsprops默認(rèn)值

getInitialStatestate默認(rèn)值

掛載階段

componentWillMount組件初始化渲染前調(diào)用

render組件渲染

componentDidMount組件掛載到DOM后調(diào)用

更新階段

componentWillReceiveProps組件將要接收新props前調(diào)用

shouldComponentUpdate組件是否需要更新

componentWillUpdate組件更新前調(diào)用

render組件渲染

componentDidUpdate組件更新后調(diào)用

卸載階段

componentWillUnmount組件卸載前調(diào)用

16生命周期

初始化階段

constructor構(gòu)造函數(shù)

getDefaultPropsprops默認(rèn)值

getInitialStatestate默認(rèn)值

掛載階段

staticgetDerivedStateFromProps(props,state)

render

componentDidMount

getDerivedStateFromProps:組件每次被rerender的時(shí)候,包括在組件構(gòu)建之后(虛擬dom之后垦藏,實(shí)際dom掛載之前)鸳谜,每次獲取新的props或state之后咐扭;每次接收新的props之后都會(huì)返回一個(gè)對(duì)象作為新的state蝗肪,返回null則說明不需要更新state;配合componentDidUpdate辛馆,可以覆蓋componentWillReceiveProps的所有用法

更新階段

staticgetDerivedStateFromProps(props,state)

shouldComponentUpdate

render

getSnapshotBeforeUpdate(prevProps,prevState)

componentDidUpdate

getSnapshotBeforeUpdate:觸發(fā)時(shí)間:update發(fā)生的時(shí)候昙篙,在render之后,在組件dom渲染之前缴挖;返回一個(gè)值映屋,作為componentDidUpdate的第三個(gè)參數(shù)同蜻;配合componentDidUpdate, 可以覆蓋componentWillUpdate的所有用法

卸載階段

componentWillUnmount

錯(cuò)誤處理

componentDidCatch

React16新的生命周期棄用了componentWillMount湾蔓、componentWillReceivePorps默责,componentWillUpdate新增了getDerivedStateFromProps、getSnapshotBeforeUpdate來代替棄用的三個(gè)鉤子函數(shù)。

React16并沒有刪除這三個(gè)鉤子函數(shù)葡缰,但是不能和新增的鉤子函數(shù)混用泛释,React17將會(huì)刪除這三個(gè)鉤子函數(shù)温算,新增了對(duì)錯(cuò)誤的處理(componentDidCatch)

setState是同步的還是異步的注竿?

生命周期和合成事件中

在React的生命周期和合成事件中巩割,React仍然處于他的更新機(jī)制中,這時(shí)無論調(diào)用多少次setState愈犹,都會(huì)不會(huì)立即執(zhí)行更新漩怎,而是將要更新的·存入_pendingStateQueue,將要更新的組件存入dirtyComponent饭玲。

當(dāng)上一次更新機(jī)制執(zhí)行完畢咱枉,以生命周期為例蚕断,所有組件入挣,即最頂層組件didmount后會(huì)將批處理標(biāo)志設(shè)置為false径筏。這時(shí)將取出dirtyComponent中的組件以及_pendingStateQueue中的state進(jìn)行更新滋恬。這樣就可以確保組件不會(huì)被重新渲染多次。

? componentDidMount() {

? ? this.setState({

? ? ? index: this.state.index + 1

? ? })

? ? console.log('state', this.state.index);

? }

所以带斑,如上面的代碼勋磕,當(dāng)我們?cè)趫?zhí)行setState后立即去獲取state敢靡,這時(shí)是獲取不到更新后的state的啸胧,因?yàn)樘幱赗eact的批處理機(jī)制中纺念,state被暫存起來柠辞,待批處理機(jī)制完成之后,統(tǒng)一進(jìn)行更新习勤。

所以图毕。setState本身并不是異步的,而是React的批處理機(jī)制給人一種異步的假象囤官。

異步代碼和原生事件中

? componentDidMount() {

? ? setTimeout(() => {

? ? ? console.log('調(diào)用setState');

? ? ? this.setState({

? ? ? ? index: this.state.index + 1

? ? ? })

? ? ? console.log('state', this.state.index);

? ? }, 0);

? }

如上面的代碼党饮,當(dāng)我們?cè)诋惒酱a中調(diào)用setState時(shí)刑顺,根據(jù)JavaScript的異步機(jī)制饲常,會(huì)將異步代碼先暫存贝淤,等所有同步代碼執(zhí)行完畢后在執(zhí)行播聪,這時(shí)React的批處理機(jī)制已經(jīng)走完犬耻,處理標(biāo)志設(shè)被設(shè)置為false执泰,這時(shí)再調(diào)用setState即可立即執(zhí)行更新术吝,拿到更新后的結(jié)果排苍。

在原生事件中調(diào)用setState并不會(huì)出發(fā)React的批處理機(jī)制,所以立即能拿到最新結(jié)果传藏。

最佳實(shí)踐

setState的第二個(gè)參數(shù)接收一個(gè)函數(shù)毯侦,該函數(shù)會(huì)在React的批處理機(jī)制完成之后調(diào)用侈离,所以你想在調(diào)用setState后立即獲取更新后的值卦碾,請(qǐng)?jiān)谠摶卣{(diào)函數(shù)中獲取。

? this.setState({ index: this.state.index + 1 }, () => {

? ? ? console.log(this.state.index);

? ? })

推薦閱讀:由實(shí)際問題探究setState的執(zhí)行機(jī)制

為什么有時(shí)連續(xù)多次setState只有一次生效济榨?

例如下面的代碼腿短,兩次打印出的結(jié)果是相同的:

? componentDidMount() {

? ? this.setState({ index: this.state.index + 1 }, () => {

? ? ? console.log(this.state.index);

? ? })

? ? this.setState({ index: this.state.index + 1 }, () => {

? ? ? console.log(this.state.index);

? ? })

? }

原因就是React會(huì)批處理機(jī)制中存儲(chǔ)的多個(gè)setState進(jìn)行合并橘忱,來看下React源碼中的_assign函數(shù)钝诚,類似于Object的assign:

_assign(nextState, typeof partial === 'function' ? partial.call(inst, nextState, props, context) : partial);

如果傳入的是對(duì)象凝颇,很明顯會(huì)被合并成一次疹鳄,所以上面的代碼兩次打印的結(jié)果是相同的:

Object.assign(

? nextState,

? {index: state.index+ 1},

? {index: state.index+ 1}

)

注意瘪弓,assign函數(shù)中對(duì)函數(shù)做了特殊處理腺怯,處理第一個(gè)參數(shù)傳入的是函數(shù)呛占,函數(shù)的參數(shù)preState是前一次合并后的結(jié)果肴茄,所以計(jì)算結(jié)果是準(zhǔn)確的:

? componentDidMount() {

? ? this.setState((state, props) => ({

? ? ? ? index: state.index + 1

? ? }), () => {

? ? ? console.log(this.state.index);

? ? })

? ? this.setState((state, props) => ({

? ? ? ? index: state.index + 1

? ? }), () => {

? ? ? console.log(this.state.index);

? ? })

? }

所以上面的代碼兩次打印的結(jié)果是不同的仅叫。

最佳實(shí)踐

React會(huì)對(duì)多次連續(xù)的setState進(jìn)行合并惑芭,如果你想立即使用上次setState后的結(jié)果進(jìn)行下一次setState遂跟,可以讓setState接收一個(gè)函數(shù)而不是一個(gè)對(duì)象幻锁。這個(gè)函數(shù)用上一個(gè)state作為第一個(gè)參數(shù)边臼,將此次更新被應(yīng)用時(shí)的props做為第二個(gè)參數(shù)柠并。

React如何實(shí)現(xiàn)自己的事件機(jī)制臼予?

React事件并沒有綁定在真實(shí)的Dom節(jié)點(diǎn)上粘拾,而是通過事件代理缰雇,在最外層的document上對(duì)事件進(jìn)行統(tǒng)一分發(fā)。

組件掛載疏之、更新時(shí):

通過lastProps锋爪、nextProps判斷是否新增、刪除事件分別調(diào)用事件注冊(cè)沃呢、卸載方法薄霜。

調(diào)用EventPluginHub的enqueuePutListener進(jìn)行事件存儲(chǔ)

獲取document對(duì)象惰瓜。

根據(jù)事件名稱(如onClick、onCaptureClick)判斷是進(jìn)行冒泡還是捕獲备禀。

判斷是否存在addEventListener方法曲尸,否則使用attachEvent(兼容IE)另患。

給document注冊(cè)原生事件回調(diào)為dispatchEvent(統(tǒng)一的事件分發(fā)機(jī)制)昆箕。

事件初始化:

EventPluginHub負(fù)責(zé)管理React合成事件的callback鹏倘,它將callback存儲(chǔ)在listenerBank中肺稀,另外還存儲(chǔ)了負(fù)責(zé)合成事件的Plugin话原。

獲取綁定事件的元素的唯一標(biāo)識(shí)key繁仁。

將callback根據(jù)事件類型黄虱,元素的唯一標(biāo)識(shí)key存儲(chǔ)在listenerBank中捻浦。

listenerBank的結(jié)構(gòu)是:listenerBank[registrationName][key]朱灿。

觸發(fā)事件時(shí):

觸發(fā)document注冊(cè)原生事件的回調(diào)dispatchEvent

獲取到觸發(fā)這個(gè)事件最深一級(jí)的元素

遍歷這個(gè)元素的所有父元素盗扒,依次對(duì)每一級(jí)元素進(jìn)行處理。

構(gòu)造合成事件缕碎。

將每一級(jí)的合成事件存儲(chǔ)在eventQueue事件隊(duì)列中池户。

遍歷eventQueue煞檩。

通過isPropagationStopped判斷當(dāng)前事件是否執(zhí)行了阻止冒泡方法斟湃。

如果阻止了冒泡凝赛,停止遍歷墓猎,否則通過executeDispatch執(zhí)行合成事件毙沾。

釋放處理完成的事件左胞。

React在自己的合成事件中重寫了stopPropagation方法烤宙,將isPropagationStopped設(shè)置為true躺枕,然后在遍歷每一級(jí)事件的過程中根據(jù)此遍歷判斷是否繼續(xù)執(zhí)行拐云。這就是React自己實(shí)現(xiàn)的冒泡機(jī)制。

推薦閱讀:【React深入】React事件機(jī)制

為何React事件要自己綁定this膳帕?

在上面提到的事件處理流程中备闲,React在document上進(jìn)行統(tǒng)一的事件分發(fā)恬砂,dispatchEvent通過循環(huán)調(diào)用所有層級(jí)的事件來模擬事件冒泡和捕獲泻骤。

在React源碼中狱掂,當(dāng)具體到某一事件處理函數(shù)將要調(diào)用時(shí)趋惨,將調(diào)用invokeGuardedCallback方法器虾。

function invokeGuardedCallback(name, func, a) {

? try {

? ? func(a);

? } catch (x) {

? ? if (caughtError === null) {

? ? ? caughtError = x;

? ? }

? }

}

可見兆沙,事件處理函數(shù)是直接調(diào)用的葛圃,并沒有指定調(diào)用的組件库正,所以不進(jìn)行手動(dòng)綁定的情況下直接獲取到的this是不準(zhǔn)確的诀诊,所以我們需要手動(dòng)將當(dāng)前組件綁定到this上属瓣。

原生事件和React事件的區(qū)別抡蛙?

React事件使用駝峰命名,而不是全部小寫魂迄。

通過JSX, 你傳遞一個(gè)函數(shù)作為事件處理程序粗截,而不是一個(gè)字符串。

在React中你不能通過返回false來阻止默認(rèn)行為捣炬。必須明確調(diào)用preventDefault熊昌。

React的合成事件是什么绽榛?

React根據(jù)W3C規(guī)范定義了每個(gè)事件處理函數(shù)的參數(shù),即合成事件婿屹。

事件處理程序?qū)鬟fSyntheticEvent的實(shí)例,這是一個(gè)跨瀏覽器原生事件包裝器昂利。它具有與瀏覽器原生事件相同的接口届腐,包括stopPropagation()和preventDefault(),在所有瀏覽器中他們工作方式都相同蜂奸。

React合成的SyntheticEvent采用了事件池犁苏,這樣做可以大大節(jié)省內(nèi)存,而不會(huì)頻繁的創(chuàng)建和銷毀事件對(duì)象扩所。

另外围详,不管在什么瀏覽器環(huán)境下,瀏覽器會(huì)將該事件類型統(tǒng)一創(chuàng)建為合成事件祖屏,從而達(dá)到了瀏覽器兼容的目的短曾。

React和原生事件的執(zhí)行順序是什么?可以混用嗎赐劣?

React的所有事件都通過document進(jìn)行統(tǒng)一分發(fā)嫉拐。當(dāng)真實(shí)Dom觸發(fā)事件后冒泡到document后才會(huì)對(duì)React事件進(jìn)行處理。

所以原生的事件會(huì)先執(zhí)行魁兼,然后執(zhí)行React合成事件婉徘,最后執(zhí)行真正在document上掛載的事件

React事件和原生事件最好不要混用。原生事件中如果執(zhí)行了stopPropagation方法咐汞,則會(huì)導(dǎo)致其他React事件失效盖呼。因?yàn)樗性氐氖录o法冒泡到document上,導(dǎo)致所有的React事件都將無法被觸發(fā)化撕。几晤。

虛擬Dom是什么?

在原生的JavaScript程序中植阴,我們直接對(duì)DOM進(jìn)行創(chuàng)建和更改蟹瘾,而DOM元素通過我們監(jiān)聽的事件和我們的應(yīng)用程序進(jìn)行通訊。

而React會(huì)先將你的代碼轉(zhuǎn)換成一個(gè)JavaScript對(duì)象掠手,然后這個(gè)JavaScript對(duì)象再轉(zhuǎn)換成真實(shí)DOM憾朴。這個(gè)JavaScript對(duì)象就是所謂的虛擬DOM。

當(dāng)我們需要?jiǎng)?chuàng)建或更新元素時(shí)喷鸽,React首先會(huì)讓這個(gè)VitrualDom對(duì)象進(jìn)行創(chuàng)建和更改众雷,然后再將VitrualDom對(duì)象渲染成真實(shí)DOM。

當(dāng)我們需要對(duì)DOM進(jìn)行事件監(jiān)聽時(shí),首先對(duì)VitrualDom進(jìn)行事件監(jiān)聽砾省,VitrualDom會(huì)代理原生的DOM事件從而做出響應(yīng)鸡岗。

推薦閱讀:【React深入】深入分析虛擬DOM的渲染過程和特性

虛擬Dom比普通Dom更快嗎?

很多文章說VitrualDom可以提升性能编兄,這一說法實(shí)際上是很片面的纤房。

直接操作DOM是非常耗費(fèi)性能的,這一點(diǎn)毋庸置疑翻诉。但是React使用VitrualDom也是無法避免操作DOM的。

如果是首次渲染捌刮,VitrualDom不具有任何優(yōu)勢碰煌,甚至它要進(jìn)行更多的計(jì)算,消耗更多的內(nèi)存绅作。

VitrualDom的優(yōu)勢在于React的Diff算法和批處理策略芦圾,React在頁面更新之前,提前計(jì)算好了如何進(jìn)行更新和渲染DOM俄认。實(shí)際上个少,這個(gè)計(jì)算過程我們?cè)谥苯硬僮鱀OM時(shí),也是可以自己判斷和實(shí)現(xiàn)的眯杏,但是一定會(huì)耗費(fèi)非常多的精力和時(shí)間夜焦,而且往往我們自己做的是不如React好的。所以岂贩,在這個(gè)過程中React幫助我們"提升了性能"茫经。

所以,我更傾向于說萎津,VitrualDom幫助我們提高了開發(fā)效率卸伞,在重復(fù)渲染時(shí)它幫助我們計(jì)算如何更高效的更新,而不是它比DOM操作更快锉屈。

虛擬Dom中的$$typeof屬性的作用是什么荤傲?

ReactElement中有一個(gè)$$typeof屬性,它被賦值為REACT_ELEMENT_TYPE:

var REACT_ELEMENT_TYPE =

? (typeof Symbol === 'function' && Symbol.for && Symbol.for('react.element')) ||

? 0xeac7;

可見颈渊,$$typeof是一個(gè)Symbol類型的變量遂黍,這個(gè)變量可以防止XSS。

如果你的服務(wù)器有一個(gè)漏洞俊嗽,允許用戶存儲(chǔ)任意JSON對(duì)象妓湘, 而客戶端代碼需要一個(gè)字符串,這可能會(huì)成為一個(gè)問題:

// JSON

let expectedTextButGotJSON = {

? type: 'div',

? props: {

? ? dangerouslySetInnerHTML: {

? ? ? __html: '/* put your exploit here */'

? ? },

? },

};

let message = { text: expectedTextButGotJSON };

<p>

? {message.text}

</p>

JSON中不能存儲(chǔ)Symbol類型的變量乌询。

ReactElement.isValidElement函數(shù)用來判斷一個(gè)React組件是否是有效的榜贴,下面是它的具體實(shí)現(xiàn)。

ReactElement.isValidElement = function (object) {

? return typeof object === 'object' && object !== null && object.$$typeof === REACT_ELEMENT_TYPE;

};

可見React渲染時(shí)會(huì)把沒有$$typeof標(biāo)識(shí),以及規(guī)則校驗(yàn)不通過的組件過濾掉唬党。

當(dāng)你的環(huán)境不支持Symbol時(shí)鹃共,$$typeof被賦值為0xeac7,至于為什么驶拱,React開發(fā)者給出了答案:

0xeac7看起來有點(diǎn)像React霜浴。

React組件的渲染流程是什么?

使用React.createElement或JSX編寫React組件蓝纲,實(shí)際上所有的JSX代碼最后都會(huì)轉(zhuǎn)換成React.createElement(...)阴孟,Babel幫助我們完成了這個(gè)轉(zhuǎn)換的過程。

createElement函數(shù)對(duì)key和ref等特殊的props進(jìn)行處理税迷,并獲取defaultProps對(duì)默認(rèn)props進(jìn)行賦值永丝,并且對(duì)傳入的孩子節(jié)點(diǎn)進(jìn)行處理,最終構(gòu)造成一個(gè)ReactElement對(duì)象(所謂的虛擬DOM)箭养。

ReactDOM.render將生成好的虛擬DOM渲染到指定容器上慕嚷,其中采用了批處理、事務(wù)等機(jī)制并且對(duì)特定瀏覽器進(jìn)行了性能優(yōu)化毕泌,最終轉(zhuǎn)換為真實(shí)DOM喝检。

為什么代碼中一定要引入React?

JSX只是為React.createElement(component,props,...children)方法提供的語法糖撼泛。

所有的JSX代碼最后都會(huì)轉(zhuǎn)換成React.createElement(...)挠说,Babel幫助我們完成了這個(gè)轉(zhuǎn)換的過程。

所以使用了JSX的代碼都必須引入React愿题。

為什么React組件首字母必須大寫纺涤?

babel在編譯時(shí)會(huì)判斷JSX中組件的首字母,當(dāng)首字母為小寫時(shí)抠忘,其被認(rèn)定為原生DOM標(biāo)簽撩炊,createElement的第一個(gè)變量被編譯為字符串;當(dāng)首字母為大寫時(shí)崎脉,其被認(rèn)定為自定義組件拧咳,createElement的第一個(gè)變量被編譯為對(duì)象;

React在渲染真實(shí)Dom時(shí)做了哪些性能優(yōu)化囚灼?

在IE(8-11)和Edge瀏覽器中骆膝,一個(gè)一個(gè)插入無子孫的節(jié)點(diǎn),效率要遠(yuǎn)高于插入一整個(gè)序列化完整的節(jié)點(diǎn)樹灶体。

React通過lazyTree阅签,在IE(8-11)和Edge中進(jìn)行單個(gè)節(jié)點(diǎn)依次渲染節(jié)點(diǎn),而在其他瀏覽器中則首先將整個(gè)大的DOM結(jié)構(gòu)構(gòu)建好蝎抽,然后再整體插入容器政钟。

并且,在單獨(dú)渲染節(jié)點(diǎn)時(shí),React還考慮了fragment等特殊節(jié)點(diǎn)养交,這些節(jié)點(diǎn)則不會(huì)一個(gè)一個(gè)插入渲染精算。

什么是高階組件?如何實(shí)現(xiàn)碎连?

高階組件可以看作React對(duì)裝飾模式的一種實(shí)現(xiàn)灰羽,高階組件就是一個(gè)函數(shù),且該函數(shù)接受一個(gè)組件作為參數(shù)鱼辙,并返回一個(gè)新的組件廉嚼。

高階組件(HOC)是React中的高級(jí)技術(shù),用來重用組件邏輯倒戏。但高階組件本身并不是ReactAPI怠噪。它只是一種模式,這種模式是由React自身的組合性質(zhì)必然產(chǎn)生的峭梳。

function visible(WrappedComponent) {

? return class extends Component {

? ? render() {

? ? ? const { visible, ...props } = this.props;

? ? ? if (visible === false) return null;

? ? ? return <WrappedComponent {...props} />;

? ? }

? }

}

上面的代碼就是一個(gè)HOC的簡單應(yīng)用,函數(shù)接收一個(gè)組件作為參數(shù)蹂喻,并返回一個(gè)新組件葱椭,新組建可以接收一個(gè)visible props,根據(jù)visible的值來判斷是否渲染Visible口四。

我們可以通過以下兩種方式實(shí)現(xiàn)高階組件:

屬性代理

函數(shù)返回一個(gè)我們自己定義的組件孵运,然后在render中返回要包裹的組件,這樣我們就可以代理所有傳入的props蔓彩,并且決定如何渲染治笨,實(shí)際上 ,這種方式生成的高階組件就是原組件的父組件赤嚼,上面的函數(shù)visible就是一個(gè)HOC屬性代理的實(shí)現(xiàn)方式旷赖。

function proxyHOC(WrappedComponent) {

? return class extends Component {

? ? render() {

? ? ? return <WrappedComponent {...this.props} />;

? ? }

? }

}

對(duì)比原生組件增強(qiáng)的項(xiàng):

可操作所有傳入的props

可操作組件的生命周期

可操作組件的static方法

獲取refs

反向繼承

返回一個(gè)組件,繼承原組件更卒,在render中調(diào)用原組件的render等孵。由于繼承了原組件,能通過this訪問到原組件的生命周期蹂空、props俯萌、state、render等上枕,相比屬性代理它能操作更多的屬性咐熙。

function inheritHOC(WrappedComponent) {

? return class extends WrappedComponent {

? ? render() {

? ? ? return super.render();

? ? }

? }

}

對(duì)比原生組件增強(qiáng)的項(xiàng):

可操作所有傳入的props

可操作組件的生命周期

可操作組件的static方法

獲取refs

可操作state

可以渲染劫持

推薦閱讀:【React深入】從Mixin到HOC再到Hook

HOC在業(yè)務(wù)場景中有哪些實(shí)際應(yīng)用場景?

HOC可以實(shí)現(xiàn)的功能:

組合渲染

條件渲染

操作props

獲取refs

狀態(tài)管理

操作state

渲染劫持

HOC在業(yè)務(wù)中的實(shí)際應(yīng)用場景:

日志打點(diǎn)

權(quán)限控制

雙向綁定

表單校驗(yàn)

具體實(shí)現(xiàn)請(qǐng)參考我這篇文章:https://juejin.im/post/5cad39b3f265da03502b1c0a

高階組件(HOC)和Mixin的異同點(diǎn)是什么辨萍?

Mixin和HOC都可以用來解決React的代碼復(fù)用問題棋恼。

圖片來源于網(wǎng)絡(luò)

Mixin可能會(huì)相互依賴,相互耦合,不利于代碼維護(hù)

不同的Mixin中的方法可能會(huì)相互沖突

Mixin非常多時(shí)蘸泻,組件是可以感知到的琉苇,甚至還要為其做相關(guān)處理,這樣會(huì)給代碼造成滾雪球式的復(fù)雜性

而HOC的出現(xiàn)可以解決這些問題:

高階組件就是一個(gè)沒有副作用的純函數(shù)悦施,各個(gè)高階組件不會(huì)互相依賴耦合

高階組件也有可能造成沖突并扇,但我們可以在遵守約定的情況下避免這些行為

高階組件并不關(guān)心數(shù)據(jù)使用的方式和原因,而被包裹的組件也不關(guān)心數(shù)據(jù)來自何處抡诞。高階組件的增加不會(huì)為原組件增加負(fù)擔(dān)

Hook有哪些優(yōu)勢穷蛹?

減少狀態(tài)邏輯復(fù)用的風(fēng)險(xiǎn)

Hook和Mixin在用法上有一定的相似之處,但是Mixin引入的邏輯和狀態(tài)是可以相互覆蓋的昼汗,而多個(gè)Hook之間互不影響肴熏,這讓我們不需要在把一部分精力放在防止避免邏輯復(fù)用的沖突上。在不遵守約定的情況下使用HOC也有可能帶來一定沖突顷窒,比如props覆蓋等等蛙吏,使用Hook則可以避免這些問題。

避免地獄式嵌套

大量使用HOC的情況下讓我們的代碼變得嵌套層級(jí)非常深鞋吉,使用HOC鸦做,我們可以實(shí)現(xiàn)扁平式的狀態(tài)邏輯復(fù)用,而避免了大量的組件嵌套谓着。

讓組件更容易理解

在使用class組件構(gòu)建我們的程序時(shí)泼诱,他們各自擁有自己的狀態(tài),業(yè)務(wù)邏輯的復(fù)雜使這些組件變得越來越龐大赊锚,各個(gè)生命周期中會(huì)調(diào)用越來越多的邏輯治筒,越來越難以維護(hù)。使用Hook舷蒲,可以讓你更大限度的將公用邏輯抽離耸袜,將一個(gè)組件分割成更小的函數(shù),而不是強(qiáng)制基于生命周期方法進(jìn)行分割牲平。

使用函數(shù)代替class

相比函數(shù)句灌,編寫一個(gè)class可能需要掌握更多的知識(shí),需要注意的點(diǎn)也越多欠拾,比如this指向胰锌、綁定事件等等。另外藐窄,計(jì)算機(jī)理解一個(gè)class比理解一個(gè)函數(shù)更快资昧。Hooks讓你可以在classes之外使用更多React的新特性。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末荆忍,一起剝皮案震驚了整個(gè)濱河市格带,隨后出現(xiàn)的幾起案子撤缴,更是在濱河造成了極大的恐慌,老刑警劉巖叽唱,帶你破解...
    沈念sama閱讀 217,509評(píng)論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件屈呕,死亡現(xiàn)場離奇詭異,居然都是意外死亡棺亭,警方通過查閱死者的電腦和手機(jī)虎眨,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,806評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來镶摘,“玉大人嗽桩,你說我怎么就攤上這事∑喔遥” “怎么了碌冶?”我有些...
    開封第一講書人閱讀 163,875評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長涝缝。 經(jīng)常有香客問我扑庞,道長,這世上最難降的妖魔是什么拒逮? 我笑而不...
    開封第一講書人閱讀 58,441評(píng)論 1 293
  • 正文 為了忘掉前任罐氨,我火速辦了婚禮,結(jié)果婚禮上消恍,老公的妹妹穿的比我還像新娘岂昭。我一直安慰自己以现,他們只是感情好狠怨,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,488評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著邑遏,像睡著了一般佣赖。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上记盒,一...
    開封第一講書人閱讀 51,365評(píng)論 1 302
  • 那天憎蛤,我揣著相機(jī)與錄音,去河邊找鬼纪吮。 笑死俩檬,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的碾盟。 我是一名探鬼主播棚辽,決...
    沈念sama閱讀 40,190評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼冰肴!你這毒婦竟也來了屈藐?” 一聲冷哼從身側(cè)響起榔组,我...
    開封第一講書人閱讀 39,062評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎联逻,沒想到半個(gè)月后搓扯,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,500評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡包归,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,706評(píng)論 3 335
  • 正文 我和宋清朗相戀三年锨推,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片箫踩。...
    茶點(diǎn)故事閱讀 39,834評(píng)論 1 347
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡爱态,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出境钟,到底是詐尸還是另有隱情锦担,我是刑警寧澤,帶...
    沈念sama閱讀 35,559評(píng)論 5 345
  • 正文 年R本政府宣布慨削,位于F島的核電站洞渔,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏缚态。R本人自食惡果不足惜磁椒,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,167評(píng)論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望玫芦。 院中可真熱鬧浆熔,春花似錦、人聲如沸桥帆。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,779評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽老虫。三九已至叶骨,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間祈匙,已是汗流浹背忽刽。 一陣腳步聲響...
    開封第一講書人閱讀 32,912評(píng)論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留夺欲,地道東北人跪帝。 一個(gè)月前我還...
    沈念sama閱讀 47,958評(píng)論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像些阅,于是被迫代替她去往敵國和親伞剑。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,779評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容

  • 作為一個(gè)合格的開發(fā)者扑眉,不要只滿足于編寫了可以運(yùn)行的代碼纸泄。而要了解代碼背后的工作原理赖钞;不要只滿足于自己的程序...
    六個(gè)周閱讀 8,448評(píng)論 1 33
  • 40、React 什么是React聘裁?React 是一個(gè)用于構(gòu)建用戶界面的框架(采用的是MVC模式):集中處理VIE...
    萌妹撒閱讀 1,016評(píng)論 0 1
  • 3. JSX JSX是對(duì)JavaScript語言的一個(gè)擴(kuò)展語法雪营, 用于生產(chǎn)React“元素”,建議在描述UI的時(shí)候...
    pixels閱讀 2,824評(píng)論 0 24
  • React簡介 (1)簡介 React 起源于 Facebook 的內(nèi)部項(xiàng)目衡便,因?yàn)樵摴緦?duì)市場上所有 JavaSc...
    魚魚吃貓貓閱讀 1,626評(píng)論 1 6
  • HTML模版 之后出現(xiàn)的React代碼嵌套入模版中献起。 1. Hello world 這段代碼將一個(gè)一級(jí)標(biāo)題插入到指...
    ryanho84閱讀 6,232評(píng)論 0 9