<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          【面試題】697- React萬(wàn)字長(zhǎng)文面試題梳理

          共 17272字,需瀏覽 35分鐘

           ·

          2020-08-27 13:02

          原文地址:www.imooc.com/article/309371

          1、React 中 keys的作用是什么

          KeysReact 用于追蹤哪些列表中元素被修改、被添加或者被移除的輔助標(biāo)識(shí)

          在開(kāi)發(fā)過(guò)程中我們需要保證某個(gè)元素的 key 在其同級(jí)元素中具有唯一性。在 React Diff 算法中React 會(huì)借助元素的 Key 值來(lái)判斷該元素是新近創(chuàng)建的還是被移動(dòng)而來(lái)的元素從而減少不必要的元素重渲染。此外React 還需要借助 Key 值來(lái)判斷元素與本地狀態(tài)的關(guān)聯(lián)關(guān)系因此我們絕不可忽視轉(zhuǎn)換函數(shù)中 Key 的重要性

          2、傳入 setState 函數(shù)的第二個(gè)參數(shù)的作用是什么

          該函數(shù)會(huì)在 setState 函數(shù)調(diào)用完成并且組件開(kāi)始重渲染的時(shí)候被調(diào)用我們可以用該函數(shù)來(lái)監(jiān)聽(tīng)渲染是否完成

          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
          ??}
          })

          3、React 中 refs 的作用是什么

          RefsReact 提供給我們的安全訪問(wèn) DOM元素或者某個(gè)組件實(shí)例的句柄可以為元素添加ref屬性然后在回調(diào)函數(shù)中接受該元素在 DOM 樹(shù)中的句柄該值會(huì)作為回調(diào)函數(shù)的第一個(gè)參數(shù)返回

          4、在生命周期中的哪一步你應(yīng)該發(fā)起 AJAX 請(qǐng)求

          我們應(yīng)當(dāng)將AJAX 請(qǐng)求放到 componentDidMount 函數(shù)中執(zhí)行主要原因有下

          React 下一代調(diào)和算法 Fiber 會(huì)通過(guò)開(kāi)始或停止渲染的方式優(yōu)化應(yīng)用性能其會(huì)影響到 componentWillMount 的觸發(fā)次數(shù)。對(duì)于 componentWillMount 這個(gè)生命周期函數(shù)的調(diào)用次數(shù)會(huì)變得不確定React 可能會(huì)多次頻繁調(diào)用 componentWillMount。如果我們將 AJAX 請(qǐng)求放到 componentWillMount 函數(shù)中那么顯而易見(jiàn)其會(huì)被觸發(fā)多次自然也就不是好的選擇。如果我們將AJAX 請(qǐng)求放置在生命周期的其他函數(shù)中我們并不能保證請(qǐng)求僅在組件掛載完畢后才會(huì)要求響應(yīng)。如果我們的數(shù)據(jù)請(qǐng)求在組件掛載之前就完成并且調(diào)用了setState函數(shù)將數(shù)據(jù)添加到組件狀態(tài)中對(duì)于未掛載的組件則會(huì)報(bào)錯(cuò)。而在 componentDidMount 函數(shù)中進(jìn)行 AJAX 請(qǐng)求則能有效避免這個(gè)問(wèn)題

          5、shouldComponentUpdate 的作用

          shouldComponentUpdate 允許我們手動(dòng)地判斷是否要進(jìn)行組件更新根據(jù)組件的應(yīng)用場(chǎng)景設(shè)置函數(shù)的合理返回值能夠幫我們避免不必要的更新

          6、如何告訴 React 它應(yīng)該編譯生產(chǎn)環(huán)境版

          通常情況下我們會(huì)使用 WebpackDefinePlugin 方法來(lái)將 NODE_ENV 變量值設(shè)置為 production。編譯版本中 React會(huì)忽略 propType 驗(yàn)證以及其他的告警信息同時(shí)還會(huì)降低代碼庫(kù)的大小React 使用了 Uglify 插件來(lái)移除生產(chǎn)環(huán)境下不必要的注釋等信息

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

          為了解決跨瀏覽器兼容性問(wèn)題React 會(huì)將瀏覽器原生事件Browser Native Event封裝為合成事件SyntheticEvent傳入設(shè)置的事件處理器中。這里的合成事件提供了與原生事件相同的接口不過(guò)它們屏蔽了底層瀏覽器的細(xì)節(jié)差異保證了行為的一致性。另外有意思的是React 并沒(méi)有直接將事件附著到子元素上而是以單一事件監(jiān)聽(tīng)器的方式將所有的事件發(fā)送到頂層進(jìn)行處理。這樣 React 在更新 DOM 的時(shí)候就不需要考慮如何去處理附著在 DOM 上的事件監(jiān)聽(tīng)器最終達(dá)到優(yōu)化性能的目的

          8、createElement 與 cloneElement 的區(qū)別是什么

          createElement 函數(shù)是 JSX 編譯之后使用的創(chuàng)建 React Element的函數(shù)而 cloneElement 則是用于復(fù)制某個(gè)元素并傳入新的 Props

          9、redux中間件

          中間件提供第三方插件的模式自定義攔截 action -> reducer 的過(guò)程。變?yōu)?action -> middlewares -> reducer。這種機(jī)制可以讓我們改變數(shù)據(jù)流實(shí)現(xiàn)如異步action action 過(guò)濾日志輸出異常報(bào)告等功能

          • redux-logger提供日志輸出
          • redux-thunk處理異步操作
          • redux-promise處理異步操作actionCreator的返回值是promise

          10、redux有什么缺點(diǎn)

          一個(gè)組件所需要的數(shù)據(jù)必須由父組件傳過(guò)來(lái)而不能像flux中直接從store取。當(dāng)一個(gè)組件相關(guān)數(shù)據(jù)更新時(shí)即使父組件不需要用到這個(gè)組件父組件還是會(huì)重新render可能會(huì)有效率影響或者需要寫復(fù)雜的shouldComponentUpdate進(jìn)行判斷。

          11、react組件的劃分業(yè)務(wù)組件技術(shù)組件

          根據(jù)組件的職責(zé)通常把組件分為UI組件和容器組件。UI 組件負(fù)責(zé) UI 的呈現(xiàn)容器組件負(fù)責(zé)管理數(shù)據(jù)和邏輯。兩者通過(guò)React-Redux 提供connect方法聯(lián)系起來(lái)

          12、react舊版生命周期函數(shù)

          初始化階段

          • getDefaultProps:獲取實(shí)例的默認(rèn)屬性
          • getInitialState:獲取每個(gè)實(shí)例的初始化狀態(tài)
          • componentWillMount組件即將被裝載、渲染到頁(yè)面上
          • render:組件在這里生成虛擬的DOM節(jié)點(diǎn)
          • componentDidMount:組件真正在被裝載之后

          運(yùn)行中狀態(tài)

          • componentWillReceiveProps:組件將要接收到屬性的時(shí)候調(diào)用
          • shouldComponentUpdate:組件接受到新屬性或者新?tīng)顟B(tài)的時(shí)候可以返回false接收數(shù)據(jù)后不更新阻止render調(diào)用后面的函數(shù)不會(huì)被繼續(xù)執(zhí)行了
          • componentWillUpdate:組件即將更新不能修改屬性和狀態(tài)
          • render:組件重新描繪
          • componentDidUpdate:組件已經(jīng)更新

          銷毀階段

          componentWillUnmount:組件即將銷毀新版生命周期

          在新版本中React 官方對(duì)生命周期有了新的 變動(dòng)建議:

          • 使用getDerivedStateFromProps替換componentWillMount
          • 使用getSnapshotBeforeUpdate替換componentWillUpdate
          • 避免使用componentWillReceiveProps

          其實(shí)該變動(dòng)的原因正是由于上述提到的 Fiber。首先從上面我們知道 React 可以分成 reconciliationcommit兩個(gè)階段對(duì)應(yīng)的生命周期如下:

          • reconciliation

          • componentWillMount

          • componentWillReceiveProps

          • shouldComponentUpdate

          • componentWillUpdate

          • commit

          • componentDidMoun

          • componentDidUpdate

          • componentWillUnmount

          Fiberreconciliation 階段進(jìn)行了任務(wù)分割涉及到 暫停 和 重啟因此可能會(huì)導(dǎo)致 reconciliation 中的生命周期函數(shù)在一次更新渲染循環(huán)中被 多次調(diào)用 的情況產(chǎn)生一些意外錯(cuò)誤

          新版的建議生命周期如下:

          class?Component?extends?React.Component?{
          ??//?替換?`componentWillReceiveProps`?
          ??//?初始化和?update?時(shí)被調(diào)用
          ??//?靜態(tài)函數(shù)無(wú)法使用?this
          ??static?getDerivedStateFromProps(nextProps,?prevState)?{}
          ??
          ??//?判斷是否需要更新組件
          ??//?可以用于組件性能優(yōu)化
          ??shouldComponentUpdate(nextProps,?nextState)?{}
          ??
          ??//?組件被掛載后觸發(fā)
          ??componentDidMount()?{}
          ??
          ??//?替換?componentWillUpdate
          ??//?可以在更新之前獲取最新?dom?數(shù)據(jù)
          ??getSnapshotBeforeUpdate()?{}
          ??
          ??//?組件更新后調(diào)用
          ??componentDidUpdate()?{}
          ??
          ??//?組件即將銷毀
          ??componentWillUnmount()?{}
          ??
          ??//?組件已銷毀
          ??componentDidUnMount()?{}
          }

          使用建議:

          • constructor初始化 state
          • componentDidMount中進(jìn)行事件監(jiān)聽(tīng)并在componentWillUnmount中解綁事件
          • componentDidMount中進(jìn)行數(shù)據(jù)的請(qǐng)求而不是在componentWillMount
          • 需要根據(jù) props 更新 state 時(shí)使用getDerivedStateFromProps(nextProps, prevState)
          • props 需要自己存儲(chǔ)以便比較
          public?static?getDerivedStateFromProps(nextProps,?prevState)?{
          ?//?當(dāng)新?props?中的?data?發(fā)生變化時(shí)同步更新到?state?上
          ?if?(nextProps.data?!==?prevState.data)?{
          ??return?{
          ???data:?nextProps.data
          ??}
          ?}?else?{
          ??return?null1
          ?}
          }

          可以在componentDidUpdate監(jiān)聽(tīng) props 或者 state 的變化例如:

          componentDidUpdate(prevProps)?{
          ?//?當(dāng)?id?發(fā)生變化時(shí)重新獲取數(shù)據(jù)
          ?if?(this.props.id?!==?prevProps.id)?{
          ??this.fetchData(this.props.id);
          ?}
          }

          componentDidUpdate使用setState`時(shí)必須加條件否則將進(jìn)入死循環(huán)

          shouldComponentUpdate: 默認(rèn)每次調(diào)用setState一定會(huì)最終走到 diff 階段但可以通過(guò)shouldComponentUpdate的生命鉤子返回false來(lái)直接阻止后面的邏輯執(zhí)行通常是用于做條件渲染優(yōu)化渲染的性能。

          13、react性能優(yōu)化是哪個(gè)周期函數(shù)

          shouldComponentUpdate 這個(gè)方法用來(lái)判斷是否需要調(diào)用render方法重新描繪dom。因?yàn)閐om的描繪非常消耗性能如果我們能在

          shouldComponentUpdate方法中能夠?qū)懗龈鼉?yōu)化的dom diff算法可以極大的提高性能

          14、為什么虛擬dom會(huì)提高性能

          虛擬dom相當(dāng)于在js和真實(shí)dom中間加了一個(gè)緩存利用dom diff算法避免了沒(méi)有必要的dom操作從而提高性能

          具體實(shí)現(xiàn)步驟如下

          • JavaScript對(duì)象結(jié)構(gòu)表示 DOM 樹(shù)的結(jié)構(gòu)然后用這個(gè)樹(shù)構(gòu)建一個(gè)真正的 DOM 樹(shù)插到文檔當(dāng)中
          • 當(dāng)狀態(tài)變更的時(shí)候重新構(gòu)造一棵新的對(duì)象樹(shù)。然后用新的樹(shù)和舊的樹(shù)進(jìn)行比較記錄兩棵樹(shù)差異
          • 把2所記錄的差異應(yīng)用到步驟1所構(gòu)建的真正的DOM樹(shù)上視圖就更新

          15、diff算法?

          • 把樹(shù)形結(jié)構(gòu)按照層級(jí)分解只比較同級(jí)元素。
          • 給列表結(jié)構(gòu)的每個(gè)單元添加唯一的key屬性方便比較。
          • React 只會(huì)匹配相同 classcomponent這里面的class指的是組件的名字
          • 合并操作調(diào)用componentsetState 方法的時(shí)候, React 將其標(biāo)記為 - dirty.到每一個(gè)事件循環(huán)結(jié)束, React 檢查所有標(biāo)記 dirtycomponent重新繪制.
          • 選擇性子樹(shù)渲染。開(kāi)發(fā)人員可以重寫shouldComponentUpdate提高diff的性能

          16、react性能優(yōu)化方案

          • 重寫shouldComponentUpdate來(lái)避免不必要的dom操作
          • 使用production 版本的react.js
          • 使用key來(lái)幫助React識(shí)別列表中所有子組件的最小變化

          17、簡(jiǎn)述flux 思想

          • Flux 的最大特點(diǎn)就是數(shù)據(jù)的"單向流動(dòng)"。

          • 用戶訪問(wèn) View

          • View發(fā)出用戶的 Action

          • Dispatcher 收到Action要求 Store 進(jìn)行相應(yīng)的更新

          • Store 更新后發(fā)出一個(gè)"change"事件

          • View 收到"change"事件后更新頁(yè)面

          18、說(shuō)說(shuō)你用react有什么坑點(diǎn)

          1. JSX做表達(dá)式判斷時(shí)候需要強(qiáng)轉(zhuǎn)為boolean類型

          如果不使用 !!b 進(jìn)行強(qiáng)轉(zhuǎn)數(shù)據(jù)類型會(huì)在頁(yè)面里面輸出 0。

          render()?{
          ??const?b?=?0;
          ??return?<div>
          ????{
          ??????!!b?&&?<div>這是一段文本div>

          ????}
          ??div>
          }
          1. 盡量不要在 componentWillReviceProps 里使用 setState如果一定要使用那么需要判斷結(jié)束條件不然會(huì)出現(xiàn)無(wú)限重渲染導(dǎo)致頁(yè)面崩潰

          2. 給組件添加ref時(shí)候盡量不要使用匿名函數(shù)因?yàn)楫?dāng)組件更新的時(shí)候匿名函數(shù)會(huì)被當(dāng)做新的prop處理讓ref屬性接受到新函數(shù)的時(shí)候react內(nèi)部會(huì)先清空ref也就是會(huì)以null為回調(diào)參數(shù)先執(zhí)行一次ref這個(gè)props然后在以該組件的實(shí)例執(zhí)行一次ref所以用匿名函數(shù)做ref的時(shí)候有的時(shí)候去ref賦值后的屬性會(huì)取到null

          3. 遍歷子節(jié)點(diǎn)的時(shí)候不要用 index 作為組件的 key 進(jìn)行傳入

          19、我現(xiàn)在有一個(gè)button要用react在上面綁定點(diǎn)擊事件要怎么做

          class?Demo?{
          ??render()?{
          ????return?<button?onClick={(e)?=>?{
          ??????alert('我點(diǎn)擊了按鈕')
          ????}}>
          ??????按鈕
          ????button>

          ??}
          }

          你覺(jué)得你這樣設(shè)置點(diǎn)擊事件會(huì)有什么問(wèn)題嗎

          由于onClick使用的是匿名函數(shù)所有每次重渲染的時(shí)候會(huì)把該onClick當(dāng)做一個(gè)新的prop來(lái)處理會(huì)將內(nèi)部緩存的onClick事件進(jìn)行重新賦值所以相對(duì)直接使用函數(shù)來(lái)說(shuō)可能有一點(diǎn)的性能下降

          修改

          class?Demo?{

          ??onClick?=?(e)?=>?{
          ????alert('我點(diǎn)擊了按鈕')
          ??}

          ??render()?{
          ????return?<button?onClick={this.onClick}>
          ??????按鈕
          ????button>

          ??}

          20、react 的虛擬dom是怎么實(shí)現(xiàn)的

          首先說(shuō)說(shuō)為什么要使用Virturl DOM因?yàn)椴僮髡鎸?shí)DOM的耗費(fèi)的性能代價(jià)太高所以react內(nèi)部使用js實(shí)現(xiàn)了一套dom結(jié)構(gòu)在每次操作在和真實(shí)dom之前使用實(shí)現(xiàn)好的diff算法對(duì)虛擬dom進(jìn)行比較遞歸找出有變化的dom節(jié)點(diǎn)然后對(duì)其進(jìn)行更新操作。為了實(shí)現(xiàn)虛擬DOM我們需要把每一種節(jié)點(diǎn)類型抽象成對(duì)象每一種節(jié)點(diǎn)類型有自己的屬性也就是prop每次進(jìn)行diff的時(shí)候react會(huì)先比較該節(jié)點(diǎn)類型假如節(jié)點(diǎn)類型不一樣那么react會(huì)直接刪除該節(jié)點(diǎn)然后直接創(chuàng)建新的節(jié)點(diǎn)插入到其中假如節(jié)點(diǎn)類型一樣那么會(huì)比較prop是否有更新假如有prop不一樣那么react會(huì)判定該節(jié)點(diǎn)有更新那么重渲染該節(jié)點(diǎn)然后在對(duì)其子節(jié)點(diǎn)進(jìn)行比較一層一層往下直到?jīng)]有子節(jié)點(diǎn)

          21、react 的渲染過(guò)程中兄弟節(jié)點(diǎn)之間是怎么處理的也就是key值不一樣的時(shí)候

          通常我們輸出節(jié)點(diǎn)的時(shí)候都是map一個(gè)數(shù)組然后返回一個(gè)ReactNode為了方便react內(nèi)部進(jìn)行優(yōu)化我們必須給每一個(gè)reactNode添加key這個(gè)key prop在設(shè)計(jì)值處不是給開(kāi)發(fā)者用的而是給react用的大概的作用就是給每一個(gè)reactNode添加一個(gè)身份標(biāo)識(shí)方便react進(jìn)行識(shí)別在重渲染過(guò)程中如果key一樣若組件屬性有所變化則react只更新組件對(duì)應(yīng)的屬性沒(méi)有變化則不更新如果key不一樣則react先銷毀該組件然后重新創(chuàng)建該組件

          23、react-router里的標(biāo)簽和標(biāo)簽有什么區(qū)別

          對(duì)比,Link組件避免了不必要的重渲染

          24、connect原理

          首先connect之所以會(huì)成功是因?yàn)?code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">Provider組件在原應(yīng)用組件上包裹一層使原來(lái)整個(gè)應(yīng)用成為Provider的子組件接收Reduxstore作為props通過(guò)context對(duì)象傳遞給子孫組件上的connectconnect做了些什么。它真正連接 ReduxReact它包在我們的容器組件的外一層它接收上面 Provider 提供的 store 里面的statedispatch傳給一個(gè)構(gòu)造函數(shù)返回一個(gè)對(duì)象以屬性形式傳給我們的容器組件

          connect是一個(gè)高階函數(shù)首先傳入mapStateToProps、mapDispatchToProps然后返回一個(gè)生產(chǎn)Component的函數(shù)(wrapWithConnect)然后再將真正的Component作為參數(shù)傳入wrapWithConnect這樣就生產(chǎn)出一個(gè)經(jīng)過(guò)包裹的Connect組件該組件具有如下特點(diǎn)

          通過(guò)props.store獲取祖先Componentstore props包括statePropsdispatchPropsparentProps,合并在一起得到nextState作為props傳給真正的Component componentDidMount時(shí)添加事件this.store.subscribe(this.handleChange)實(shí)現(xiàn)頁(yè)面交互shouldComponentUpdate時(shí)判斷是否有避免進(jìn)行渲染提升頁(yè)面性能并得到nextState componentWillUnmount時(shí)移除注冊(cè)的事件this.handleChange

          由于connect的源碼過(guò)長(zhǎng)我們只看主要邏輯

          export?default?function?connect(mapStateToProps,?mapDispatchToProps,?mergeProps,?options?=?{})?{
          ??return?function?wrapWithConnect(WrappedComponent)?{
          ????class?Connect?extends?Component?{
          ??????constructor(props,?context)?{
          ????????//?從祖先Component處獲得store
          ????????this.store?=?props.store?||?context.store
          ????????this.stateProps?=?computeStateProps(this.store,?props)
          ????????this.dispatchProps?=?computeDispatchProps(this.store,?props)
          ????????this.state?=?{?storeState:?null?}
          ????????//?對(duì)stateProps、dispatchProps、parentProps進(jìn)行合并
          ????????this.updateState()
          ??????}
          ??????shouldComponentUpdate(nextProps,?nextState)?{
          ????????//?進(jìn)行判斷當(dāng)數(shù)據(jù)發(fā)生改變時(shí)Component重新渲染
          ????????if?(propsChanged?
          ????????||?mapStateProducedChange?
          ????????||?dispatchPropsChanged)?{
          ??????????this.updateState(nextProps)
          ????????????return?true
          ??????????}
          ????????}
          ????????componentDidMount()?{
          ??????????//?改變Component的state
          ??????????this.store.subscribe(()?=?{
          ????????????this.setState({
          ??????????????storeState:?this.store.getState()
          ????????????})
          ??????????})
          ????????}
          ????????render()?{
          ??????????//?生成包裹組件Connect
          ??????????return?(
          ????????????<WrappedComponent?{...this.nextState}?/>
          ??????????)
          ????????}
          ??????}
          ??????Connect.contextTypes?=?{
          ????????store:?storeShape
          ??????}
          ??????return?Connect;
          ????}
          ??}

          25、Redux實(shí)現(xiàn)原理解析

          為什么要用redux

          React中數(shù)據(jù)在組件中是單向流動(dòng)的數(shù)據(jù)從一個(gè)方向父組件流向子組件通過(guò)props,所以兩個(gè)非父子組件之間通信就相對(duì)麻煩redux的出現(xiàn)就是為了解決state里面的數(shù)據(jù)問(wèn)題

          Redux設(shè)計(jì)理念

          Redux是將整個(gè)應(yīng)用狀態(tài)存儲(chǔ)到一個(gè)地方上稱為store,里面保存著一個(gè)狀態(tài)樹(shù)store tree,組件可以派發(fā)(dispatch)行為(action)給store,而不是直接通知其他組件組件內(nèi)部通過(guò)訂閱store中的狀態(tài)state來(lái)刷新自己的視圖

          image

          Redux三大原則

          1.唯一數(shù)據(jù)源

          整個(gè)應(yīng)用的state都被存儲(chǔ)到一個(gè)狀態(tài)樹(shù)里面并且這個(gè)狀態(tài)樹(shù)只存在于唯一的store

          2.保持只讀狀態(tài)

          state是只讀的唯一改變state的方法就是觸發(fā)actionaction是一個(gè)用于描述以發(fā)生時(shí)間的普通對(duì)象

          3.數(shù)據(jù)改變只能通過(guò)純函數(shù)來(lái)執(zhí)行

          使用純函數(shù)來(lái)執(zhí)行修改為了描述action如何改變state的你需要編寫reducers

          Redux源碼

          let?createStore?=?(reducer)?=>?{
          ????let?state;
          ????//獲取狀態(tài)對(duì)象
          ????//存放所有的監(jiān)聽(tīng)函數(shù)
          ????let?listeners?=?[];
          ????let?getState?=?()?=>?state;
          ????//提供一個(gè)方法供外部調(diào)用派發(fā)action
          ????let?dispath?=?(action)?=>?{
          ????????//調(diào)用管理員reducer得到新的state
          ????????state?=?reducer(state,?action);
          ????????//執(zhí)行所有的監(jiān)聽(tīng)函數(shù)
          ????????listeners.forEach((l)?=>?l())
          ????}
          ????//訂閱狀態(tài)變化事件當(dāng)狀態(tài)改變發(fā)生之后執(zhí)行監(jiān)聽(tīng)函數(shù)
          ????let?subscribe?=?(listener)?=>?{
          ????????listeners.push(listener);
          ????}
          ????dispath();
          ????return?{
          ????????getState,
          ????????dispath,
          ????????subscribe
          ????}
          }
          let?combineReducers=(renducers)=>{
          ????//傳入一個(gè)renducers管理組返回的是一個(gè)renducer
          ????return?function(state={},action={}){
          ????????let?newState={};
          ????????for(var?attr?in?renducers){
          ????????????newState[attr]=renducers[attr](state[attr],action)

          ????????}
          ????????return?newState;
          ????}
          }
          export?{createStore,combineReducers};

          26、pureComponent和FunctionComponent區(qū)別

          PureComponentComponent完全相同但是在shouldComponentUpdate實(shí)現(xiàn)中PureComponent使用了propsstate的淺比較。主要作用是用來(lái)提高某些特定場(chǎng)景的性能

          27 react hooks它帶來(lái)了那些便利

          在類定義中我們可以使用到許多 React 特性例如 state、 各種組件生命周期鉤子等但是在函數(shù)定義中我們卻無(wú)能為力因此 React 16.8 版本推出了一個(gè)新功能 (React Hooks)通過(guò)它可以更好的在函數(shù)定義組件中使用 React 特性。

          好處:

          注意:

          避免在 循環(huán)/條件判斷/嵌套函數(shù) 中調(diào)用 hooks保證調(diào)用順序的穩(wěn)定只有 函數(shù)定義組件 和 hooks 可以調(diào)用 hooks避免在 類組件 或者 普通函數(shù) 中調(diào)用不能在useEffect中使用useStateReact 會(huì)報(bào)錯(cuò)提示類組件不會(huì)被替換或廢棄不需要強(qiáng)制改造類組件兩種方式能并存重要鉤子

          狀態(tài)鉤子 (useState): 用于定義組件的State其到類定義中this.state的功能

          //?useState?只接受一個(gè)參數(shù):?初始狀態(tài)
          //?返回的是組件名和更改該組件對(duì)應(yīng)的函數(shù)
          const?[flag,?setFlag]?=?useState(true);
          //?修改狀態(tài)
          setFlag(false)
          ?
          //?上面的代碼映射到類定義中:
          this.state?=?{
          ?flag:?true?
          }
          const?flag?=?this.state.flag
          const?setFlag?=?(bool)?=>?{
          ????this.setState({
          ????????flag:?bool,
          ????})
          }

          生命周期鉤子 (useEffect):

          類定義中有許多生命周期函數(shù)而在 React Hooks 中也提供了一個(gè)相應(yīng)的函數(shù) (useEffect)這里可以看做componentDidMountcomponentDidUpdatecomponentWillUnmount的結(jié)合。

          useEffect(()?=>?{
          ?//?組件掛載后執(zhí)行事件綁定
          ?console.log('on')
          ?addEventListener()
          ?//?組件?update?時(shí)會(huì)執(zhí)行事件解綁
          ?return?()?=>?{
          ??console.log('off')
          ??removeEventListener()
          ?}
          },?[source]);


          //?每次?source?發(fā)生改變時(shí)執(zhí)行結(jié)果(以類定義的生命周期便于大家理解):
          //?---?DidMount?---
          //?'on'
          //?---?DidUpdate?---
          //?'off'
          //?'on'
          //?---?DidUpdate?---
          //?'off'
          //?'on'
          //?---?WillUnmount?---?
          //?'off'

          通過(guò)第二個(gè)參數(shù)我們便可模擬出幾個(gè)常用的生命周期:

          const?useMounted?=?()?=>?{
          ????const?[mounted,?setMounted]?=?useState(false);
          ????useEffect(()?=>?{
          ????????!mounted?&&?setMounted(true);
          ????????return?()?=>?setMounted(false);
          ????},?[]);
          ????return?mounted;
          }
          componentDidUpdate:?useEffect每次均會(huì)執(zhí)行其實(shí)就是排除了?DidMount?后即可
          const?mounted?=?useMounted()?
          useEffect(()?=>?{
          ????mounted?&&?fn()
          })

          其它內(nèi)置鉤子:

          function?useTitle(title)?{
          ??useEffect(
          ????()?=>?{
          ??????document.title?=?title;
          ????});
          }

          //?使用:
          function?Home()?{
          ?const?title?=?'我是首頁(yè)'
          ?useTitle(title)
          ?
          ?return?(
          ??<div>{title}div>
          ?)
          }

          28、React Portal 有哪些使用場(chǎng)景

          在以前 react 中所有的組件都會(huì)位于 #app 下而使用 Portals 提供了一種脫離 #app 的組件因此 Portals 適合脫離文檔流(out of flow) 的組件特別是 position: absoluteposition: fixed的組件。比如模態(tài)框通知警告goTop 等。

          以下是官方一個(gè)模態(tài)框的示例可以在以下地址中測(cè)試效果

          <html>
          ??<body>
          ????<div?id="app">div>
          ????<div?id="modal">div>
          ????<div?id="gotop">div>
          ????<div?id="alert">div>
          ??body>
          html>
          const?modalRoot?=?document.getElementById('modal');

          class?Modal?extends?React.Component?{
          ??constructor(props)?{
          ????super(props);
          ????this.el?=?document.createElement('div');
          ??}

          ??componentDidMount()?{
          ????modalRoot.appendChild(this.el);
          ??}

          ??componentWillUnmount()?{
          ????modalRoot.removeChild(this.el);
          ??}

          ??render()?{
          ????return?ReactDOM.createPortal(
          ??????this.props.children,
          ??????this.el,
          ????);
          ??}
          }

          React Hooks當(dāng)中的useEffect是如何區(qū)分生命周期鉤子的

          useEffect可以看成是componentDidMountcomponentDidUpdatecomponentWillUnmount三者的結(jié)合。useEffect(callback, [source])接收兩個(gè)參數(shù)調(diào)用方式如下

          ?useEffect(()?=>?{
          ???console.log('mounted');
          ???
          ???return?()?=>?{
          ???????console.log('willUnmount');
          ???}
          ?},?[source]);

          生命周期函數(shù)的調(diào)用主要是通過(guò)第二個(gè)參數(shù)[source]來(lái)進(jìn)行控制有如下幾種情況

          29、react和vue的區(qū)別

          相同點(diǎn)

          不同點(diǎn)

          30、什么是高階組件(HOC)

          高階組件(Higher Order Componennt)本身其實(shí)不是組件而是一個(gè)函數(shù)這個(gè)函數(shù)接收一個(gè)元組件作為參數(shù)然后返回一個(gè)新的增強(qiáng)組件高階組件的出現(xiàn)本身也是為了邏輯復(fù)用舉個(gè)例子

          function?withLoginAuth(WrappedComponent)?{
          ??return?class?extends?React.Component?{
          ??????
          ??????constructor(props)?{
          ??????????super(props);
          ??????????this.state?=?{
          ????????????isLogin:?false
          ??????????};
          ??????}
          ??????
          ??????async?componentDidMount()?{
          ??????????const?isLogin?=?await?getLoginStatus();
          ??????????this.setState({?isLogin?});
          ??????}
          ??????
          ??????render()?{
          ????????if?(this.state.isLogin)?{
          ????????????return?<WrappedComponent?{...this.props}?/>;
          ????????}
          ????????
          ????????return?(<div>您還未登錄...div>
          );
          ??????}
          ??}
          }

          31、React實(shí)現(xiàn)的移動(dòng)應(yīng)用中如果出現(xiàn)卡頓有哪些可以考慮的優(yōu)化方案

          render函數(shù)中減少類似

          onClick={()?=>?{
          ????doSomething()
          }}

          的寫法每次調(diào)用render函數(shù)時(shí)均會(huì)創(chuàng)建一個(gè)新的函數(shù)即使內(nèi)容沒(méi)有發(fā)生任何變化也會(huì)導(dǎo)致節(jié)點(diǎn)沒(méi)必要的重渲染建議將函數(shù)保存在組件的成員對(duì)象中這樣只會(huì)創(chuàng)建一次

          32、setState

          在了解setState之前我們先來(lái)簡(jiǎn)單了解下 React 一個(gè)包裝結(jié)構(gòu): Transaction:

          事務(wù) (Transaction)

          React 中的一個(gè)調(diào)用結(jié)構(gòu)用于包裝一個(gè)方法結(jié)構(gòu)為: initialize - perform(method) - close。通過(guò)事務(wù)可以統(tǒng)一管理一個(gè)方法的開(kāi)始與結(jié)束處于事務(wù)流中表示進(jìn)程正在執(zhí)行一些操作

          setState: React 中用于修改狀態(tài)更新視圖。它具有以下特點(diǎn):

          異步與同步: setState并不是單純的異步或同步這其實(shí)與調(diào)用時(shí)的環(huán)境相關(guān):

          在合成事件 和 生命周期鉤子(除 componentDidUpdate) 中setState是"異步"的

          原因: 因?yàn)樵?code>setState的實(shí)現(xiàn)中有一個(gè)判斷: 當(dāng)更新策略正在事務(wù)流的執(zhí)行中時(shí)該組件更新會(huì)被推入dirtyComponents隊(duì)列中等待執(zhí)行否則開(kāi)始執(zhí)行batchedUpdates隊(duì)列更新

          在生命周期鉤子調(diào)用中更新策略都處于更新之前組件仍處于事務(wù)流中而componentDidUpdate是在更新之后此時(shí)組件已經(jīng)不在事務(wù)流中了因此則會(huì)同步執(zhí)行

          在合成事件中React 是基于 事務(wù)流完成的事件委托機(jī)制 實(shí)現(xiàn)也是處于事務(wù)流中

          問(wèn)題: 無(wú)法在setState后馬上從this.state上獲取更新后的值。

          解決: 如果需要馬上同步去獲取新值setState其實(shí)是可以傳入第二個(gè)參數(shù)的。setState(updater, callback)在回調(diào)中即可獲取最新值

          在 原生事件 和 setTimeoutsetState是同步的可以馬上獲取更新后的值

          原因: 原生事件是瀏覽器本身的實(shí)現(xiàn)與事務(wù)流無(wú)關(guān)自然是同步而setTimeout是放置于定時(shí)器線程中延后執(zhí)行此時(shí)事務(wù)流已結(jié)束因此也是同步

          批量更新: 在 合成事件 和 生命周期鉤子 中setState更新隊(duì)列時(shí)存儲(chǔ)的是 合并狀態(tài)(Object.assign)。因此前面設(shè)置的 key 值會(huì)被后面所覆蓋最終只會(huì)執(zhí)行一次更新

          函數(shù)式: 由于 Fiber 及 合并 的問(wèn)題官方推薦可以傳入 函數(shù) 的形式。setState(fn)在fn中返回新的state對(duì)象即可例如

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

          使用函數(shù)式可以用于避免setState的批量更新的邏輯傳入的函數(shù)將會(huì)被 順序調(diào)用

          注意事項(xiàng):

          34、HOC(高階組件)

          HOC(Higher Order Componennt) 是在 React 機(jī)制下社區(qū)形成的一種組件模式在很多第三方開(kāi)源庫(kù)中表現(xiàn)強(qiáng)大。

          簡(jiǎn)述:

          屬性代理 (Props Proxy): 返回出一個(gè)組件它基于被包裹組件進(jìn)行 功能增強(qiáng)默認(rèn)參數(shù): 可以為組件包裹一層默認(rèn)參數(shù)

          function?proxyHoc(Comp)?{
          ?return?class?extends?React.Component?{
          ??render()?{
          ???const?newProps?=?{
          ????name:?'tayde',
          ????age:?1,
          ???}
          ???return?<Comp?{...this.props}?{...newProps}?/>
          ??}
          ?}
          }

          提取狀態(tài): 可以通過(guò) props 將被包裹組件中的 state 依賴外層例如用于轉(zhuǎn)換受控組件:

          function?withOnChange(Comp)?{
          ?return?class?extends?React.Component?{
          ??constructor(props)?{
          ???super(props)
          ???this.state?=?{
          ????name:?'',
          ???}
          ??}
          ??onChangeName?=?()?=>?{
          ???this.setState({
          ????name:?'dongdong',
          ???})
          ??}
          ??render()?{
          ???const?newProps?=?{
          ????value:?this.state.name,
          ????onChange:?this.onChangeName,
          ???}
          ???return?<Comp?{...this.props}?{...newProps}?/>
          ??}
          ?}
          }

          使用姿勢(shì)如下這樣就能非常快速的將一個(gè) Input 組件轉(zhuǎn)化成受控組件。

          const?NameInput?=?props?=>?(<input?name="name"?{...props}?/>)
          export?default?withOnChange(NameInput)

          包裹組件: 可以為被包裹元素進(jìn)行一層包裝

          function?withMask(Comp)?{
          ??return?class?extends?React.Component?{
          ???render()?{
          ???return?(
          ?????

          ?????
          ????????????width:?'100%',
          ???????height:?'100%',
          ???????backgroundColor:?'rgba(0,?0,?0,?.6)',
          ?????}}?
          ????

          ???)
          ???}
          ??}
          }

          反向繼承 (Inheritance Inversion): 返回出一個(gè)組件繼承于被包裹組件常用于以下操作

          function?IIHoc(Comp)?{
          ????return?class?extends?Comp?{
          ????????render()?{
          ????????????return?super.render();
          ????????}
          ????};
          }

          渲染劫持 (Render Highjacking)

          條件渲染: 根據(jù)條件渲染不同的組件

          function?withLoading(Comp)?{
          ??return?class?extends?Comp?{
          ????render()?{
          ??????if(this.props.isLoading)?{
          ??????????return?<Loading?/>
          ??????}?else?{
          ??????????return?super.render()
          ??????}
          ????}
          ??};
          }

          可以直接修改被包裹組件渲染出的 React 元素樹(shù)

          操作狀態(tài) (Operate State): 可以直接通過(guò) this.state 獲取到被包裹組件的狀態(tài)并進(jìn)行操作。但這樣的操作容易使 state 變得難以追蹤不易維護(hù)謹(jǐn)慎使用。

          應(yīng)用場(chǎng)景:

          權(quán)限控制通過(guò)抽象邏輯統(tǒng)一對(duì)頁(yè)面進(jìn)行權(quán)限判斷按不同的條件進(jìn)行頁(yè)面渲染:

          function?withAdminAuth(WrappedComponent)?{
          ??return?class?extends?React.Component?{
          ???constructor(props){
          ????super(props)
          ????this.state?=?{
          ????????isAdmin:?false,
          ????}
          ???}?
          ???async?componentWillMount()?{
          ?????const?currentRole?=?await?getCurrentUserRole();
          ?????this.setState({
          ?????????isAdmin:?currentRole?===?'Admin',
          ?????});
          ???}
          ???render()?{
          ?????if?(this.state.isAdmin)?{
          ???????return?<Comp?{...this.props}?/>;
          ?????}?else?{
          ???????return?(<div>您沒(méi)有權(quán)限查看該頁(yè)面請(qǐng)聯(lián)系管理員div>
          );
          ?????}
          ???}
          ??};
          }

          性能監(jiān)控包裹組件的生命周期進(jìn)行統(tǒng)一埋點(diǎn):

          function?withTiming(Comp)?{
          ????return?class?extends?Comp?{
          ????????constructor(props)?{
          ????????????super(props);
          ????????????this.start?=?Date.now();
          ????????????this.end?=?0;
          ????????}
          ????????componentDidMount()?{
          ????????????super.componentDidMount?&&?super.componentDidMount();
          ????????????this.end?=?Date.now();
          ????????????console.log(`${WrappedComponent.name}?組件渲染時(shí)間為?${this.end?-?this.start}?ms`);
          ????????}
          ????????render()?{
          ????????????return?super.render();
          ????????}
          ????};
          }

          代碼復(fù)用可以將重復(fù)的邏輯進(jìn)行抽象。

          使用注意:

          35、React如何進(jìn)行組件/邏輯復(fù)用?

          拋開(kāi)已經(jīng)被官方棄用的Mixin,組件抽象的技術(shù)目前有三種比較主流:

          高階組件:

          36、你對(duì) Time Slice的理解?

          時(shí)間分片

          37、setState到底是異步還是同步?

          先給出答案: 有時(shí)表現(xiàn)出異步,有時(shí)表現(xiàn)出同步



          1. JavaScript 重溫系列(22篇全)
          2. ECMAScript 重溫系列(10篇全)
          3. JavaScript設(shè)計(jì)模式 重溫系列(9篇全)
          4.?正則 / 框架 / 算法等 重溫系列(16篇全)
          5.?Webpack4 入門(上)||?Webpack4 入門(下)
          6.?MobX 入門(上)?||??MobX 入門(下)
          7.?70+篇原創(chuàng)系列匯總

          回復(fù)“加群”與大佬們一起交流學(xué)習(xí)~

          點(diǎn)擊“閱讀原文”查看70+篇原創(chuàng)文章

          點(diǎn)這,與大家一起分享本文吧~


          瀏覽 39
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  亚洲我操 | 国产露脸150部国语对白 | 最近中文字幕mv第一季歌词免费 | 欧美艹逼网 | 农村少妇久久久久久久 |