<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>

          一名中/高級(jí)前端工程師的自檢清單-React 篇

          共 13570字,需瀏覽 28分鐘

           ·

          2021-12-11 14:32

          點(diǎn)擊上方 前端Q,關(guān)注公眾號(hào)

          回復(fù)加群,加入前端Q技術(shù)交流群

          你真的了解 React 嗎?我們?cè)诿嬖囍型婕?React 時(shí),第一個(gè)問題就是“解釋 React 是什么”。解釋一種技術(shù)是什么,在面試中也是非常常見的引起 話題的題目。本篇文章我就帶你掌握這一類概念題的解答技巧。

          一. 說說對(duì) React 的理解,有哪些特性

          官方的解釋:React 是一個(gè) UI 庫,它的核心思想是UI=F(data), 即界面的呈現(xiàn)是由函數(shù)傳入的參數(shù)決定的

          開發(fā)者不再需要關(guān)心界面時(shí)如何渲染的,只要關(guān)心數(shù)據(jù)的生成和傳遞,這大大提高的開發(fā)者的開發(fā)效率,節(jié)省了開發(fā)時(shí)間

          其次 React 設(shè)計(jì)的

          • 使用類似 HTML 的JSX語法來描述視圖
          • 通過虛擬DOM修改真實(shí)DOM
          • 通過setState修改數(shù)據(jù)
          • 在不同的生命周期階段做不同的事
          • 源碼底層對(duì)真實(shí) DOM 事件進(jìn)行封裝,使用事件委托的方式來捕獲 DOM 事件
          • ....

          等特性進(jìn)一步簡化的 真實(shí) DOM 操作的復(fù)雜性

          二. 說說真實(shí) DOM 與虛擬 DOM 的區(qū)別,優(yōu)缺點(diǎn)

          虛擬DOM

          2.1 虛擬 DOM 是什么

          • 真實(shí)DOM就是我們?cè)跒g覽器開發(fā)者工具中看到的DOM結(jié)構(gòu)
          • 虛擬DOM簡單來說就是 JS 對(duì)象,此對(duì)象中的字段包含了對(duì)真實(shí)DOM的描述:
            • type:是什么標(biāo)簽/元素
            • props:標(biāo)簽/元素有哪些屬性
            • children:是否有子元素
          a

          2.2 虛擬 DOM 大概是如何工作的

          當(dāng) DOM 操作(渲染更新)比較頻繁時(shí),

          React 底層會(huì)先將前后兩次的虛擬DOM 樹進(jìn)行對(duì)比,

          定位出具體需要更新的部分,生成一個(gè)補(bǔ)丁集,

          最后只把“補(bǔ)丁”打在需要更新的那部分真實(shí)DOM 上,實(shí)現(xiàn)精準(zhǔn)的“差量更新”。

          2.3 虛擬 DOM 的優(yōu)點(diǎn)

          1. 解決了頻繁操作真實(shí) DOM 的低效率工作-不直接操作 DOM,數(shù)據(jù)驅(qū)動(dòng)視圖,也在一定程度上提升了性能
          2. 解決了擴(kuò)平臺(tái)開發(fā)的問題,因?yàn)樘摂M DOM 描述的東西可以是真實(shí) DOM,也可以是安卓界面。IOS 界面等等,這就可以對(duì)接不同平臺(tái)的渲染邏輯。從而實(shí)現(xiàn)"一次編碼,多端運(yùn)行"(如 React,React Native)

          2.4 虛擬 DOM 的缺點(diǎn)

          如果當(dāng)虛擬 DOM 的構(gòu)建和diff的過程相對(duì)復(fù)雜(比如很多遞歸遍歷等操作),那么虛擬 DOM 的 JS 計(jì)算是比較耗時(shí)的

          三. 說說 Diff 算法

          Diff算法

          一般的原始 diff 思路算法復(fù)雜度是O(n^3),即循環(huán)遞歸進(jìn)行樹節(jié)點(diǎn)的一一對(duì)比

          但 React 的 diff 算法O (n) 復(fù)雜度的思路

          當(dāng)對(duì)比兩棵虛擬 DOM 樹時(shí),React 首先比較兩棵樹的根節(jié)點(diǎn)。不同類型的根節(jié)點(diǎn)元素會(huì)有不同的形態(tài)

          當(dāng)對(duì)比兩個(gè)相同類型的 React 元素時(shí),React 會(huì)保留 DOM 節(jié)點(diǎn),僅比對(duì)及更新有改變的屬性。

          1. 當(dāng)根節(jié)點(diǎn)為不同類型的元素時(shí),React 會(huì)拆卸原有的樹并且建立起新的樹,這大大減少了 Diff 過程中冗余的遞歸操作
          2. 當(dāng)對(duì)比兩個(gè)相同類型的 React 元素時(shí),React 會(huì)保留 DOM 節(jié)點(diǎn),僅比對(duì)及更新有改變的屬性
          3. 列表形式的子元素比較:React 引入了 key 屬性。當(dāng)子元素?fù)碛?key 時(shí),React 使用 key 來匹配原有樹上的子元素以及最新樹上的子元素,如果 key不同 不同則會(huì)拆卸原有的 key 節(jié)點(diǎn)并且建立起新的 key 節(jié)點(diǎn)

          詳細(xì)內(nèi)容請(qǐng)參考React 官方文檔- Diffing 算法[2]

          四. 說說 React 聲明周期有哪些不同階段,每個(gè)階段對(duì)應(yīng)的方法是什么

          image.png

          4.1 創(chuàng)建階段

          1. constructor():組件的構(gòu)造函數(shù),組件更新到界面上之前會(huì)先調(diào)用

            • 用于初始化內(nèi)部狀態(tài),很少使用
            • 唯一可以直接修改 state 的地方
          2. static getDerivedStateFromProps(nextProps, prevState):用于從外部的屬性去初始化一些內(nèi)部的狀態(tài)

            • 當(dāng) state 需要從 props 初始化時(shí)使用
            • 盡量不要使用,維護(hù) state/props 狀態(tài)一致性會(huì)增加復(fù)雜度
            • 每次 render 都會(huì)調(diào)用
            • 典型場(chǎng)景: 表單控件獲取默認(rèn)值
          3. render()::組件必須定義的一個(gè)生命周期方法,用來描述 虛擬 DOM 結(jié)構(gòu)

          4. componentDidMount(): 用于數(shù)據(jù)請(qǐng)求,定義一些外部資源等等副作用

            • UI 渲染完成后調(diào)用
            • 只執(zhí)行一次
            • 典型場(chǎng)景:獲取外部資源

          4.2 更新階段

          1. static getDerivedStateFromProps(nextProps, prevState)
          2. shouldComponentUpdate(nextProps, nextState):告訴組件是否需要重新渲染,用于性能優(yōu)化,比如判定指定 props 發(fā)生改變,組件才進(jìn)行重新渲染
            • 決定虛擬 DOM 是否需要重繪
            • 一般可以由 PureComponent 自動(dòng)實(shí)現(xiàn)
            • 典型場(chǎng)景:性能優(yōu)化
          3. render()
          4. getSnapshotBeforeUpdate(prevProps, prevState)
            • 在最近一次渲染輸出(提交到 DOM 節(jié)點(diǎn))之前調(diào)用,state 已更新
            • componentDidUpdate 搭配使用
            • 典型場(chǎng)景:捕獲 render 之前的 DOM 狀態(tài)
          5. componentDidUpdate(prevProps, prevState)
            • 每次 UI 更新時(shí)被調(diào)用
            • 典型場(chǎng)景:頁面需要根據(jù) props 變化重新獲取數(shù)據(jù)

          4.3 卸載階段

          1. componentWillUnmount(): 做些資源釋放,卸載副作用的事情
          • 此方法中可以執(zhí)行必要的清理操作,例如,清除 timer,取消網(wǎng)絡(luò)請(qǐng)求或清除在

          詳細(xì)內(nèi)容請(qǐng)參考React 知識(shí)體系之生命周期及使用場(chǎng)景[3]

          五. 說說對(duì) State 和 Props 的理解,有什么區(qū)別

          • state用于組件內(nèi)部數(shù)據(jù)傳遞,state 數(shù)據(jù)可以通過this.setSate或者useState進(jìn)行修改

          • props用于組件外部組件數(shù)據(jù)傳遞,props不能直接修改.主要使用場(chǎng)景是:

            • 兄弟組件通信
            • 父子組件通信
            • "爺孫組件"組件通信
          • props的使用范圍雖然更加廣泛,但也有其局限性:對(duì)于嵌套層次較深的組件,如果使用props傳遞數(shù)據(jù),會(huì)導(dǎo)致代碼冗余,增加數(shù)據(jù)傳遞的復(fù)雜度

          六. super 和 super(props)有什么區(qū)別

          在 JavaScript 中,super 指的是父類構(gòu)造函數(shù)。(在我們的示例中,它指向 React.Component 實(shí)現(xiàn)。)

          在調(diào)用父類的構(gòu)造函數(shù)之前,你是不能在 constructor 中使用 this 關(guān)鍵字的。JavaScript 不允許這個(gè)行為

          class Checkbox extends React.Component {
            constructor(props) {
              // ??  還不能使用 `this`
              super(props);
              // ?  現(xiàn)在可以了
              this.state = { isOntrue };
            }
            // ...
          }
          復(fù)制代碼

          為什么一定要傳遞 props 呢?為了讓 React.Component 構(gòu)造函數(shù)能夠初始化 this.props

          React 內(nèi)部代碼:

          // React 內(nèi)部
          class Component {
            constructor(props) {
              this.props = props;
              // ...
            }
          }
          復(fù)制代碼

          實(shí)例代碼:

          class Button extends React.Component {
            constructor(props) {
              super(); // ? We forgot to pass props
              console.log(props); // ? {}
              console.log(this.props); // ? undefined
            }
            // ...
          }
          復(fù)制代碼
          class Button extends React.Component {
            constructor(props) {
              super(props); // ? We passed props
              console.log(props); // ? {}
              console.log(this.props); // ? {}
            }
            // ...
          }
          復(fù)制代碼

          有了 Hooks 以后,我們幾乎就不需要 superthis

          詳細(xì)內(nèi)容請(qǐng)參考為什么我們要寫 super(props) ?[4]

          七. 說說 React 中的 setState 機(jī)制

          setState

          7.1 合成事件、鉤子函數(shù)中的 setState

          • 在鉤子函數(shù)中 setSate 拿不到最新值
          • 在合成事件中執(zhí)行多個(gè)同樣的 setSate,最終只會(huì)執(zhí)行一次,并且也拿不到最新值

          原因:

          1. 一次 setState 就會(huì)觸發(fā)一次 re-render(重渲染)
          2. 為了避免頻繁的 re-ernder,setState 被設(shè)計(jì)成異步的形式
          3. 每來一個(gè) setState,就把它塞進(jìn)一個(gè)隊(duì)列里“攢起來”。等時(shí)機(jī)成熟,再把“攢起來”的 state 結(jié)果做合并(對(duì)于相同屬性的設(shè)置,React 只會(huì)為其保留最后一次的更新),最后只針對(duì)最新的 state 值走一次更新流程。這個(gè)過程,叫作**批量更新**

          7.2 setTimeout/setInterval、原生 DOM中的 setState

          • setTimeout/setInterval 中設(shè)置 setState,可以拿到最新的值
          • 原生 DOM 事件中設(shè)置 setState,可以拿到最新的值

          原因:

          setState 的“異步”并不是說內(nèi)部由異步代碼實(shí)現(xiàn),其實(shí)源碼本身執(zhí)行的過程和代碼都是同步的,

          只是合成事件和鉤子函數(shù)的調(diào)用順序在更新之前,導(dǎo)致在合成事件和鉤子函數(shù)中沒法立馬拿到更新后的值,形式了所謂的“異步”

          setState 的批量更新優(yōu)化也是建立在“異步”(合成事件、鉤子函數(shù))之上的,在原生事件和 setTimeout 中不會(huì)批量更新

          詳細(xì)內(nèi)容請(qǐng)參考setState 到底是同步的,還是異步的?[5]

          八. 說說對(duì) React 事件機(jī)制的理解

          React事件機(jī)制

          8.1 React 中的事件是什么

          React 中的事件叫合成事件:React 底層使用事件委托的方式對(duì)真實(shí) DOM 事件進(jìn)行了封裝,使合成事件具有更好的瀏覽器兼容性和性能

          8.2 合成事件的大致原理

          當(dāng)事件在具體的 DOM 節(jié)點(diǎn)上被觸發(fā)后,最終都會(huì)冒泡到 document 上,document 上所綁定的統(tǒng)一事件處理程序會(huì)將事件分發(fā)到具體的組件實(shí)例

          8.3 React 為什么要重新設(shè)計(jì)出一個(gè)合成事件

          合成事件是 React 自定義的事件對(duì)象,它符合 W3C 規(guī)范,在底層抹平了不同瀏覽器的差異,在上層面向開發(fā)者暴露統(tǒng)一的、穩(wěn)定的、與 DOM 原生事件相同的事件接口。

          開發(fā)者們由此便不必再關(guān)注煩瑣的兼容性問題,可以專注于業(yè)務(wù)邏輯的開發(fā)。

          • 雖然合成事件并不是原生 DOM 事件,但它保存了原生 DOM 事件的引用。當(dāng)你需要訪問原生 DOM 事件對(duì)象時(shí),可以通過合成事件對(duì)象的 e.nativeEvent 屬性獲取到它
          • 合成事件無法獲取到真實(shí) DOM,但可以通過 React 提供refAPI 進(jìn)行獲取

          詳細(xì)內(nèi)容請(qǐng)參考React 事件與 DOM 事件有何不同?[6]

          九. React 事件綁定的方式有哪些

          9.1 類組件

          9.1.1 render 方法中使用 bind

          這種方式在組件每次 render 渲染的時(shí)候,都會(huì)重新進(jìn)行 bind 的操作,影響性能

          class App extends React.Component {
            handleClick() {
              console.log("this > "this);
            }
            render() {
              return <div onClick={this.handleClick.bind(this)}>test</div>;
            }
          }
          復(fù)制代碼

          9.1.2 render 方法中使用箭頭函數(shù)

          通過 ES6 的上下文來將 this 的指向綁定給當(dāng)前組件,同樣在每一次 render 的時(shí)候都會(huì)生成新的方法,影響性能

          class App extends React.Component {
            handleClick() {
              console.log("this > "this);
            }
            render() {
              return <div onClick={(e) => this.handleClick(e)}>test</div>;
            }
          }
          復(fù)制代碼

          9.1.3 constructor 中 bind

          在 constructor 中預(yù)先 bind 當(dāng)前組件,可以避免在 render 操作中重復(fù)綁定

          class App extends React.Component {
            constructor(props) {
              super(props);
              this.handleClick = this.handleClick.bind(this);
            }
            handleClick() {
              console.log("this > "this);
            }
            render() {
              return <div onClick={this.handleClick}>test</div>;
            }
          }
          復(fù)制代碼

          9.1.4 定義階段使用箭頭函數(shù)綁定

          能夠避免在 render 操作中重復(fù)綁定

          class App extends React.Component {
            constructor(props) {
              super(props);
            }
            handleClick = () => {
              console.log("this > "this);
            };
            render() {
              return <div onClick={this.handleClick}>test</div>;
            }
          }
          復(fù)制代碼

          9.2 函數(shù)式組件

          • 箭頭函數(shù)

          函數(shù)組件沒有實(shí)例,因此沒有this

          const App = () => {
            handleClick = (e) => {
              console.log(e);
            };
            return <div onClick={this.handleClick}>test</div>;
          };
          復(fù)制代碼

          詳細(xì)內(nèi)容請(qǐng)參考React 構(gòu)建組件的方式有哪些[7]

          十. React 構(gòu)建組件的方式有哪些

          1. 類組件
          2. 高階組件
          3. render props
          4. 純函數(shù)組件
          5. Hooks組件
          6. 自定義Hooks

          詳細(xì)內(nèi)容請(qǐng)參考React 構(gòu)建組件的方式有哪些[8]

          十一. React 中組件通信的方式有哪些

          • 單個(gè)組件內(nèi)部數(shù)據(jù)傳遞
            • state
          • 父組件向子組件傳遞
            • props
          • 子組件向父組件傳遞
            • props
          • 兄弟組件之間的通信
            • props
          • 父組件向后代組件傳遞
            • props
            • Context API
            • Redux
            • 發(fā)布-訂閱模式
            • EventBus
          • 非關(guān)系組件傳遞
            • Context API
            • Redux
            • 發(fā)布-訂閱模式
            • EventBus

          十二. React 的 key 有什么作用

          說到 React 的 key,就要說到 React 的 Diff 算法

          詳細(xì)內(nèi)容請(qǐng)參考React 列表循環(huán)為什么需要 key[9]


          往期推薦


          大廠面試過程復(fù)盤(微信/阿里/頭條,附答案篇)
          面試題:說說事件循環(huán)機(jī)制(滿分答案來了)
          專心工作只想搞錢的前端女程序員的2020

          最后


          • 歡迎加我微信,拉你進(jìn)技術(shù)群,長期交流學(xué)習(xí)...

          • 歡迎關(guān)注「前端Q」,認(rèn)真學(xué)前端,做個(gè)專業(yè)的技術(shù)人...

          點(diǎn)個(gè)在看支持我吧

          參考資料

          [1]

          https://juejin.cn/post/6978685539985653767: https://juejin.cn/post/6978685539985653767

          [2]

          https://zh-hans.reactjs.org/docs/reconciliation.html#the-diffing-algorithm: https://link.juejin.cn?target=https%3A%2F%2Fzh-hans.reactjs.org%2Fdocs%2Freconciliation.html%23the-diffing-algorithm

          [3]

          https://juejin.cn/post/6981739846461030408: https://juejin.cn/post/6981739846461030408

          [4]

          https://overreacted.io/zh-hans/why-do-we-write-super-props/: https://link.juejin.cn?target=https%3A%2F%2Foverreacted.io%2Fzh-hans%2Fwhy-do-we-write-super-props%2F

          [5]

          https://www.yuque.com/u221766/xgl0mb/oxl3ik: https://link.juejin.cn?target=https%3A%2F%2Fwww.yuque.com%2Fu221766%2Fxgl0mb%2Foxl3ik

          [6]

          https://www.yuque.com/u221766/xgl0mb/iu68y0: https://link.juejin.cn?target=https%3A%2F%2Fwww.yuque.com%2Fu221766%2Fxgl0mb%2Fiu68y0

          [7]

          https://juejin.cn/post/6952907248393781284#heading-2: https://juejin.cn/post/6952907248393781284#heading-2

          [8]

          https://juejin.cn/post/6952907248393781284: https://juejin.cn/post/6952907248393781284

          [9]

          https://juejin.cn/post/6940974776441634823: https://juejin.cn/post/6940974776441634823


          來源:望道同學(xué)

          https://juejin.cn/post/6981831831112908831

          聲明:文章著作權(quán)歸作者所有,如有侵權(quán),請(qǐng)聯(lián)系小編刪除。


          瀏覽 41
          點(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>
                  撸一撸在线播放 | 国产精品~色哟哟 | 久久人妻无码中文字幕系列 | 777在线视频 | 丰满少妇X一88AV |