1. 【面試題】697- React萬字長文面試題梳理

        共 17272字,需瀏覽 35分鐘

         ·

        2020-08-27 13:02

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

        1、React 中 keys的作用是什么

        KeysReact 用于追蹤哪些列表中元素被修改、被添加或者被移除的輔助標識

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

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

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

        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 提供給我們的安全訪問 DOM元素或者某個組件實例的句柄可以為元素添加ref屬性然后在回調(diào)函數(shù)中接受該元素在 DOM 樹中的句柄該值會作為回調(diào)函數(shù)的第一個參數(shù)返回

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

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

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

        5、shouldComponentUpdate 的作用

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

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

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

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

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

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

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

        9、redux中間件

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

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

        10、redux有什么缺點

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

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

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

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

        初始化階段

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

        運行中狀態(tài)

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

        銷毀階段

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

        在新版本中React 官方對生命周期有了新的 變動建議:

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

        其實該變動的原因正是由于上述提到的 Fiber。首先從上面我們知道 React 可以分成 reconciliationcommit兩個階段對應的生命周期如下:

        • reconciliation

        • componentWillMount

        • componentWillReceiveProps

        • shouldComponentUpdate

        • componentWillUpdate

        • commit

        • componentDidMoun

        • componentDidUpdate

        • componentWillUnmount

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

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

        class?Component?extends?React.Component?{
        ??//?替換?`componentWillReceiveProps`?
        ??//?初始化和?update?時被調(diào)用
        ??//?靜態(tài)函數(shù)無法使用?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中進行事件監(jiān)聽并在componentWillUnmount中解綁事件
        • componentDidMount中進行數(shù)據(jù)的請求而不是在componentWillMount
        • 需要根據(jù) props 更新 state 時使用getDerivedStateFromProps(nextProps, prevState)
        • props 需要自己存儲以便比較
        public?static?getDerivedStateFromProps(nextProps,?prevState)?{
        ?//?當新?props?中的?data?發(fā)生變化時同步更新到?state?上
        ?if?(nextProps.data?!==?prevState.data)?{
        ??return?{
        ???data:?nextProps.data
        ??}
        ?}?else?{
        ??return?null1
        ?}
        }

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

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

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

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

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

        shouldComponentUpdate 這個方法用來判斷是否需要調(diào)用render方法重新描繪dom。因為dom的描繪非常消耗性能如果我們能在

        shouldComponentUpdate方法中能夠寫出更優(yōu)化的dom diff算法可以極大的提高性能

        14、為什么虛擬dom會提高性能

        虛擬dom相當于在js和真實dom中間加了一個緩存利用dom diff算法避免了沒有必要的dom操作從而提高性能

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

        • JavaScript對象結構表示 DOM 樹的結構然后用這個樹構建一個真正的 DOM 樹插到文檔當中
        • 當狀態(tài)變更的時候重新構造一棵新的對象樹。然后用新的樹和舊的樹進行比較記錄兩棵樹差異
        • 把2所記錄的差異應用到步驟1所構建的真正的DOM樹上視圖就更新

        15、diff算法?

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

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

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

        17、簡述flux 思想

        • Flux 的最大特點就是數(shù)據(jù)的"單向流動"。

        • 用戶訪問 View

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

        • Dispatcher 收到Action要求 Store 進行相應的更新

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

        • View 收到"change"事件后更新頁面

        18、說說你用react有什么坑點

        1. JSX做表達式判斷時候需要強轉為boolean類型

        如果不使用 !!b 進行強轉數(shù)據(jù)類型會在頁面里面輸出 0。

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

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

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

        3. 遍歷子節(jié)點的時候不要用 index 作為組件的 key 進行傳入

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

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

        ??}
        }

        你覺得你這樣設置點擊事件會有什么問題嗎

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

        修改

        class?Demo?{

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

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

        ??}

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

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

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

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

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

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

        24、connect原理

        首先connect之所以會成功是因為Provider組件在原應用組件上包裹一層使原來整個應用成為Provider的子組件接收Reduxstore作為props通過context對象傳遞給子孫組件上的connectconnect做了些什么。它真正連接 ReduxReact它包在我們的容器組件的外一層它接收上面 Provider 提供的 store 里面的statedispatch傳給一個構造函數(shù)返回一個對象以屬性形式傳給我們的容器組件

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

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

        由于connect的源碼過長我們只看主要邏輯

        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?}
        ????????//?對stateProps、dispatchProps、parentProps進行合并
        ????????this.updateState()
        ??????}
        ??????shouldComponentUpdate(nextProps,?nextState)?{
        ????????//?進行判斷當數(shù)據(jù)發(fā)生改變時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實現(xiàn)原理解析

        為什么要用redux

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

        Redux設計理念

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

        image

        Redux三大原則

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

        整個應用的state都被存儲到一個狀態(tài)樹里面并且這個狀態(tài)樹只存在于唯一的store

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

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

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

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

        Redux源碼

        let?createStore?=?(reducer)?=>?{
        ????let?state;
        ????//獲取狀態(tài)對象
        ????//存放所有的監(jiān)聽函數(shù)
        ????let?listeners?=?[];
        ????let?getState?=?()?=>?state;
        ????//提供一個方法供外部調(diào)用派發(fā)action
        ????let?dispath?=?(action)?=>?{
        ????????//調(diào)用管理員reducer得到新的state
        ????????state?=?reducer(state,?action);
        ????????//執(zhí)行所有的監(jiān)聽函數(shù)
        ????????listeners.forEach((l)?=>?l())
        ????}
        ????//訂閱狀態(tài)變化事件當狀態(tài)改變發(fā)生之后執(zhí)行監(jiān)聽函數(shù)
        ????let?subscribe?=?(listener)?=>?{
        ????????listeners.push(listener);
        ????}
        ????dispath();
        ????return?{
        ????????getState,
        ????????dispath,
        ????????subscribe
        ????}
        }
        let?combineReducers=(renducers)=>{
        ????//傳入一個renducers管理組返回的是一個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實現(xiàn)中PureComponent使用了propsstate的淺比較。主要作用是用來提高某些特定場景的性能

        27 react hooks它帶來了那些便利

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

        好處:

        注意:

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

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

        //?useState?只接受一個參數(shù):?初始狀態(tài)
        //?返回的是組件名和更改該組件對應的函數(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 中也提供了一個相應的函數(shù) (useEffect)這里可以看做componentDidMount、componentDidUpdatecomponentWillUnmount的結合。

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


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

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

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

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

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

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

        28、React Portal 有哪些使用場景

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

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

        <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當中的useEffect是如何區(qū)分生命周期鉤子的

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

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

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

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

        相同點

        不同點

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

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

        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實現(xiàn)的移動應用中如果出現(xiàn)卡頓有哪些可以考慮的優(yōu)化方案

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

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

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

        32、setState

        在了解setState之前我們先來簡單了解下 React 一個包裝結構: Transaction:

        事務 (Transaction)

        React 中的一個調(diào)用結構用于包裝一個方法結構為: initialize - perform(method) - close。通過事務可以統(tǒng)一管理一個方法的開始與結束處于事務流中表示進程正在執(zhí)行一些操作

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

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

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

        原因: 因為在setState的實現(xiàn)中有一個判斷: 當更新策略正在事務流的執(zhí)行中時該組件更新會被推入dirtyComponents隊列中等待執(zhí)行否則開始執(zhí)行batchedUpdates隊列更新

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

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

        問題: 無法在setState后馬上從this.state上獲取更新后的值。

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

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

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

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

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

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

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

        注意事項:

        34、HOC(高階組件)

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

        簡述:

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

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

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

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

        使用姿勢如下這樣就能非常快速的將一個 Input 組件轉化成受控組件。

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

        包裹組件: 可以為被包裹元素進行一層包裝

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

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

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

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

        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 元素樹

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

        應用場景:

        權限控制通過抽象邏輯統(tǒng)一對頁面進行權限判斷按不同的條件進行頁面渲染:

        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>您沒有權限查看該頁面請聯(lián)系管理員div>
        );
        ?????}
        ???}
        ??};
        }

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

        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}?組件渲染時間為?${this.end?-?this.start}?ms`);
        ????????}
        ????????render()?{
        ????????????return?super.render();
        ????????}
        ????};
        }

        代碼復用可以將重復的邏輯進行抽象。

        使用注意:

        35、React如何進行組件/邏輯復用?

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

        高階組件:

        36、你對 Time Slice的理解?

        時間分片

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

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



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

        回復“加群”與大佬們一起交流學習~

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

        點這,與大家一起分享本文吧~


        瀏覽 39
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        評論
        圖片
        表情
        推薦
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
          
          

            1. 999色视频 | 伊人综合久久 | 公啊~嗯去厨房里做h辣文小说 | 国产淫乱一区二区三区四区 | 美女逼逼网站 |