面試小抄 - react

生命周期

react 生命周期

其中標(biāo)紅的( componentWillMount漂问、 componentWillReceiveProps叠纷、 componentWillUpdate )是 react 16.3 版本要移除的生命周期款慨,移除原因:react 打算在17版本中阳欲,添加 async rendering 临扮, react 將一個更新過程分為 render 前后兩個階段孤个,render 前是可以被打斷(比如有緊急任務(wù))剃允,當(dāng)生命周期被打斷后,再次執(zhí)行齐鲤,并不會從斷點繼續(xù)執(zhí)行斥废,是重新執(zhí)行的,所以這些生命周期就可能會運(yùn)行多次给郊。

同時為了彌補(bǔ)失去這三個生命牡肉,react 新增了兩個生命周期: static getDerivedStateFromProps、 getSnapshotBeforeUpdate

static getDerivedStateFromProps

getDerivedStateFromProps 會在調(diào)用 render 方法之前調(diào)用淆九,并且在初始掛載及后續(xù)更新時都會被調(diào)用统锤。它應(yīng)返回一個對象來更新 state,如果返回 null 則不更新任何內(nèi)容炭庙。

此方法適用于罕見的用例饲窿,即 state 的值在任何時候都取決于 props。

static getDerivedStateFromProps(nextProps, prevState) {
  //根據(jù)nextProps和prevState計算出預(yù)期的狀態(tài)改變焕蹄,返回結(jié)果會被送給setState
  //這是一個static逾雄,簡單說應(yīng)該是一個純函數(shù)
}

getSnapshotBeforeUpdate

getSnapshotBeforeUpdate() 在最近一次渲染輸出(提交到 DOM 節(jié)點)之前調(diào)用。它使得組件能在發(fā)生更改之前從 DOM 中捕獲一些信息(例如腻脏,滾動位置)鸦泳。此生命周期的任何返回值將作為參數(shù)傳遞給 componentDidUpdate()。

getSnapshotBeforeUpdate 返回的值會做為第三個參數(shù)傳遞給 componentDidUpdate永品。

getSnapshotBeforeUpdate(prevProps, prevState) {
  ...
  return snapshot;
}

componentDidUpdate(prevProps, prevState, snapshot) {
  
}

性能優(yōu)化

shouldComponentUpdate

這是一個組件的子樹做鹰。每個節(jié)點中,SCU 代表 shouldComponentUpdate 返回的值鼎姐,而 vDOMEq 代表返回的 React 元素是否相同誊垢。最后,圓圈的顏色代表了該組件是否需要更新症见。

shouldComponentUpdate

react 父組件觸發(fā)更新時,它的所有子組件都會觸發(fā)更新(即使 props 和 state )并沒有改變殃饿,這樣時候我們在子組件中添加 shouldComponentUpdate 生命周期谋作,判斷狀態(tài)是否變更,如果沒有變更返回 false , 這個子組件就不會重新 render乎芳。

React.PureComponent

React.PureComponent 是 React 自動幫我們在 shouldComponentUpdate 做了一層淺比較遵蚜。

if (this._compositeType === CompositeTypes.PureClass) {
  shouldUpdate = !shallowEqual(prevProps, nextProps)
  || !shallowEqual(inst.state, nextState);
}

React.memo

React.memo 是一個高階組件帖池,類似于 React.PureComponent,不同于 React.memo 是 function 組件吭净,React.PureComponent 是 class 組件睡汹。

const MyComponent = React.memo(function MyComponent(props) {
  /* 使用 props 渲染 */
});

長列表優(yōu)化

  • 虛擬列表:用數(shù)組保存所有列表元素的位置,只渲染可視區(qū)內(nèi)的列表元素寂殉,當(dāng)可視區(qū)滾動時囚巴,根據(jù)滾動的 offset 大小以及所有列表元素的位置,計算在可視區(qū)應(yīng)該渲染哪些元素友扰。常用庫( react-window 彤叉、 react-virtualized )
  • 事件代理:簡單的說就是將同類行的子元素事件,綁定在一個父元素上村怪,從而達(dá)到減少事件的注冊秽浇。
  • 懶加載:常用于長列表圖片加載,組件先不渲染甚负,當(dāng)監(jiān)聽到組件可以時柬焕,在去渲染組件。常用庫( react-lazyload )

key

key 幫助 React 識別哪些元素改變了梭域,比如被添加或刪除斑举。當(dāng)子元素?fù)碛?key 時,React 使用 key 來匹配原有樹上的子元素以及最新樹上的子元素碰辅。正確的使用 key 可以使 react 的更新開銷變小懂昂。

<ul>
  <li key="2015">Duke</li>
  <li key="2016">Villanova</li>
</ul>

<ul>
  <li key="2014">Connecticut</li>
  <li key="2015">Duke</li>
  <li key="2016">Villanova</li>
</ul>

代碼復(fù)用

Mixin

概念:將公用方法包裝成 Mixin 方法,然后注入各個組件没宾,從而實現(xiàn)代碼復(fù)用凌彬。( 已經(jīng)不推薦 )

缺點:

  • 命名覆蓋:比如你在 A Mixin 中定義的 get 方法,在 B Mixin 中也定義了 get 方法循衰。
  • 復(fù)雜度高后铲敛,容易混亂:比如 Mixin 中可以調(diào)用 setState 的,當(dāng)多個 Mixin 中都調(diào)用了 setSate , state 的更新來源會變得混淆不清会钝。
  • ES6 class 語法不支持 Mixin伐蒋。

HOC(高階組件)

概念:可以理解為組件工廠,傳入原始組件迁酸,添加功能先鱼,返回新的組件。

缺點:

  • 命名覆蓋奸鬓,難以溯源:當(dāng)存在多個 HOC 時焙畔,僅僅通過新組件,并不能知道 props 是來源于哪個 HOC串远,同時如果兩個工廠宏多,傳入了相同名稱的props儿惫,就會產(chǎn)生覆蓋。
  • 靜態(tài)構(gòu)建:工廠返回的新組件伸但,不會立即執(zhí)行肾请,即 HOC 工廠函數(shù)里定義的生命周期函數(shù)只有新組建渲染時才會執(zhí)行。

Render Props

概念:Render Props 就是一個 render 函數(shù)作為 props 傳遞給了父組件更胖,使得父組件知道如何渲染子組件铛铁。

優(yōu)點:

  • 解決了命名沖突,難以溯源的問題函喉,可以通過 render props 的參數(shù)直接看到 props 來源于哪個組件避归。
  • 動態(tài)構(gòu)建,可以更好的利用組件內(nèi)的生命周期管呵。

缺點:

  • 無法利用 shouldComponentUpdate 來實現(xiàn)渲染性能的優(yōu)化梳毙。

React hooks

概念:hooks 遵循函數(shù)式編程的理念,主旨是在函數(shù)組件中引入類組件中的狀態(tài)和生命周期捐下,并且這些狀態(tài)和生命周期函數(shù)也可以被抽離账锹,實現(xiàn)復(fù)用的同時,減少函數(shù)組件的復(fù)雜性和易用性坷襟。

hooks api:

  • 基礎(chǔ):useState奸柬、 useEffect、 useContext
  • 額外:useReducer婴程、 useCallback廓奕、 useMemo、 useRef档叔、 useImperativeHandle桌粉、 useLayoutEffect、 useDebugValue

一個簡單的 custom hooks:

    
import { useEffect } from 'react';

function useTitle(title){
  useEffect(()=>{
    document.title = title;
  }, [title]);
}

虛擬 Dom diff 算法

虛擬 Dom:react 將 Dom 抽象成一個對象樹衙四,通過對比新舊兩個樹的區(qū)別(diff 算法)铃肯,然后將更新部分渲染出來。

diff 算法基于兩個策略:

  • 兩個相同組件產(chǎn)生類似的 DOM 結(jié)構(gòu)传蹈,不同的組件產(chǎn)生不同的 DOM 結(jié)構(gòu)押逼。
  • 對于同一層次的一組子節(jié)點,它們可以通過唯一的 id 進(jìn)行區(qū)分惦界。

逐層進(jìn)行節(jié)點比較

在 react 中挑格,樹的比對非常簡單,react 只會對兩棵樹進(jìn)行逐層比較沾歪,即比較處于同一層級的節(jié)點恕齐。

逐層比較

節(jié)點比較

節(jié)點比較分成兩種情況:(1)節(jié)點類型不同,(2)節(jié)點類型相同,屬性不同显歧。

情況(1):

節(jié)點不同
// DOM Diff 操作
C.destroy();
D = new D();
A.append(D);

情況(2):

//變更錢
<div style={{fontSize: '16px'}} ></div>
//變更后
<div style={{color: 'red'}} ><div/>
//執(zhí)行操作
=> removeStyle fontSize
=> addStyle color 'red'

列表節(jié)點的比較(key)

當(dāng)列表中插入 F 節(jié)點,如下圖:

列表節(jié)點的比較

這個時候就會有兩種情況:(1)節(jié)點沒有表示唯一 key 确镊,(2)節(jié)點表示了唯一 key

情況(1)結(jié)果如下圖:

列表節(jié)點的比較士骤,沒有唯一 key
//執(zhí)行過程
C unmount
D unmount
E unmount
F mount
C mount
D mount
E mount

情況(2)結(jié)果如下圖:

列表節(jié)點的比較,有唯一 key
//執(zhí)行過程
F mount

React 16.x 部分新特性

Error Boundaries

如果在組件的渲染或生命周期方法中引發(fā)錯誤蕾域,整個組件結(jié)構(gòu)就會從根節(jié)點中卸載拷肌,而不影響其他組件的渲染,可以利用 error boundaries 進(jìn)行錯誤的優(yōu)化處理旨巷。

class ErrorBoundary extends React.Component {
  constructor(props) {
    super(props);
    this.state = { hasError: false };
  }

  static getDerivedStateFromError(error) {
    // Update state so the next render will show the fallback UI.
    return { hasError: true };
  }

  componentDidCatch(error, info) {
    // You can also log the error to an error reporting service
    logErrorToMyService(error, info);
  }

  render() {
    if (this.state.hasError) {
      // You can render any custom fallback UI
      return <h1>Something went wrong.</h1>;
    }

    return this.props.children; 
  }
}

createPortal

react 支持將組建掛在到其他 dom 節(jié)點巨缘,事件還是按組件原有位置冒泡。

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

Fiber

Fiber 是對 react 核心算法 reconciliation 的更新實現(xiàn)采呐,將原本的同步更新分成兩個階段若锁。階段1(Reconciliation Phase)的任務(wù)是片段化執(zhí)行的,每個片段執(zhí)行完成之后斧吐,就會把控制權(quán)重新交給 react 調(diào)度模塊又固,如果有更高優(yōu)先級的任務(wù)就去處理,而低優(yōu)先級更新任務(wù)所做的工作則會完全作廢煤率,然后等待機(jī)會重頭再來仰冠,如果沒有就執(zhí)行下一個片段。階段2(Commit Phase)是同步執(zhí)行的蝶糯,reactDom 會根據(jù)階段1計算出來的 effect-list 來更新 DOM 洋只。

階段1涉及的生命周期(可能會執(zhí)行多次):componentWillMount、 componentWillReceiveProps昼捍、 shouldComponentUpdate识虚、 componentWillUpdate

階段2涉及的生命周期:componentDidMount、 componentDidUpdate端三、 componentWillUnmount

createContext

全新的 Context API 可以很容易實現(xiàn)祖先節(jié)點和子節(jié)點通信舷礼,并且沒有副作用。

  • React.createContext 是一個函數(shù)郊闯,它接收初始值并返回帶有 Provider 和 Consumer 組件的對象
  • Provider 發(fā)布方
  • Consumer 訂閱方
const ThemeContext = React.createContext('light');

class ThemeProvider extends React.Component {
  state = {theme: 'light'};

  render() {
    return (
      <ThemeContext.Provider value={this.state.theme}>
        {this.props.children}
      </ThemeContext.Provider>
    );
  }
}

class ThemedButton extends React.Component {
  render() {
    return (
      <ThemeContext.Consumer>
        {theme => <Button theme={theme} />}
      </ThemeContext.Consumer>
    );
  }
}

生命周期函數(shù)的更新(見上文)

React.memo(見上文)

lazy / Suspense

React.lazy() 提供了動態(tài) import 組件的能力妻献,實現(xiàn)代碼分割。

Suspense 作用是在等待組件時 suspend(暫停)渲染团赁,并顯示加載標(biāo)識育拨。

import React, {lazy, Suspense} from 'react';
const OtherComponent = lazy(() => import('./OtherComponent'));

function MyComponent() {
  return (
    <Suspense fallback={<div>Loading...</div>}>
      <OtherComponent />
    </Suspense>
  );
}

React hooks(見上文)

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市欢摄,隨后出現(xiàn)的幾起案子熬丧,更是在濱河造成了極大的恐慌,老刑警劉巖怀挠,帶你破解...
    沈念sama閱讀 217,907評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件析蝴,死亡現(xiàn)場離奇詭異害捕,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)闷畸,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,987評論 3 395
  • 文/潘曉璐 我一進(jìn)店門尝盼,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人佑菩,你說我怎么就攤上這事盾沫。” “怎么了殿漠?”我有些...
    開封第一講書人閱讀 164,298評論 0 354
  • 文/不壞的土叔 我叫張陵赴精,是天一觀的道長。 經(jīng)常有香客問我绞幌,道長蕾哟,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,586評論 1 293
  • 正文 為了忘掉前任啊奄,我火速辦了婚禮渐苏,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘菇夸。我一直安慰自己琼富,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,633評論 6 392
  • 文/花漫 我一把揭開白布庄新。 她就那樣靜靜地躺著鞠眉,像睡著了一般。 火紅的嫁衣襯著肌膚如雪择诈。 梳的紋絲不亂的頭發(fā)上械蹋,一...
    開封第一講書人閱讀 51,488評論 1 302
  • 那天,我揣著相機(jī)與錄音羞芍,去河邊找鬼哗戈。 笑死,一個胖子當(dāng)著我的面吹牛荷科,可吹牛的內(nèi)容都是我干的唯咬。 我是一名探鬼主播,決...
    沈念sama閱讀 40,275評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼畏浆,長吁一口氣:“原來是場噩夢啊……” “哼胆胰!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起刻获,我...
    開封第一講書人閱讀 39,176評論 0 276
  • 序言:老撾萬榮一對情侶失蹤蜀涨,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體厚柳,經(jīng)...
    沈念sama閱讀 45,619評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡氧枣,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,819評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了别垮。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片挑胸。...
    茶點故事閱讀 39,932評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖宰闰,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情簿透,我是刑警寧澤移袍,帶...
    沈念sama閱讀 35,655評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站老充,受9級特大地震影響葡盗,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜啡浊,卻給世界環(huán)境...
    茶點故事閱讀 41,265評論 3 329
  • 文/蒙蒙 一觅够、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧巷嚣,春花似錦喘先、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,871評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至坝茎,卻和暖如春涤姊,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背嗤放。 一陣腳步聲響...
    開封第一講書人閱讀 32,994評論 1 269
  • 我被黑心中介騙來泰國打工思喊, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人次酌。 一個月前我還...
    沈念sama閱讀 48,095評論 3 370
  • 正文 我出身青樓恨课,卻偏偏與公主長得像,于是被迫代替她去往敵國和親和措。 傳聞我的和親對象是個殘疾皇子庄呈,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,884評論 2 354

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

  • 作為一個合格的開發(fā)者,不要只滿足于編寫了可以運(yùn)行的代碼派阱。而要了解代碼背后的工作原理诬留;不要只滿足于自己的程序...
    六個周閱讀 8,448評論 1 33
  • 說在前面 關(guān)于 react 的總結(jié)過去半年就一直碎碎念著要搞起來,各(wo)種(tai)原(lan)因(le)。心...
    陳嘻嘻啊閱讀 6,867評論 7 41
  • 原教程內(nèi)容詳見精益 React 學(xué)習(xí)指南文兑,這只是我在學(xué)習(xí)過程中的一些閱讀筆記盒刚,個人覺得該教程講解深入淺出,比目前大...
    leonaxiong閱讀 2,834評論 1 18
  • 40绿贞、React 什么是React因块?React 是一個用于構(gòu)建用戶界面的框架(采用的是MVC模式):集中處理VIE...
    萌妹撒閱讀 1,016評論 0 1
  • 事件系統(tǒng) 合成事件的綁定方式 Test 合成事件的實現(xiàn)機(jī)制:事件委派和自動綁定。 React合成事件系統(tǒng)的委托機(jī)制...
    cheneyg916閱讀 386評論 0 1