react源碼解析20.總結(jié)&第一章的面試題解答
視頻課程(高效學(xué)習(xí)):進入課程
課程目錄:
6.legacy和concurrent模式入口函數(shù)
總結(jié)
至此我們介紹了react的理念邑蒋,如果解決cpu和io的瓶頸剃氧,關(guān)鍵是實現(xiàn)異步可中斷的更新
我們介紹了react源碼架構(gòu)(ui=fn(state))耍目,從scheduler開始調(diào)度(根據(jù)過期事件判斷優(yōu)先級)房交,經(jīng)過render階段的深度優(yōu)先遍歷形成effectList(中間會執(zhí)行reconcile|diff),交給commit處理真實節(jié)點(中間穿插生命周期和部分hooks)糙捺,而這些調(diào)度的過程都離不開Fiber的支撐惑芭,F(xiàn)iber是工作單元,也是節(jié)點優(yōu)先級继找、更新UpdateQueue、節(jié)點信息的載體逃沿,F(xiàn)iber雙緩存則提供了對比前后節(jié)點更新的基礎(chǔ)婴渡。我們還介紹了jsx是React.createElement的語法糖。Lane模型則提供了更細粒度的優(yōu)先級對比和計算凯亮,這一切都為concurrent mode提供了基礎(chǔ)边臼,在這之上變可以實現(xiàn)Suspense和batchedUpdate(16、17版本實現(xiàn)的邏輯不一樣)假消,18章context的valueStack和valueCursor在整個架構(gòu)中運行機制柠并,19章介紹了新版事件系統(tǒng),包括事件生產(chǎn)富拗、監(jiān)聽和觸發(fā)
面試題簡答(詳見視頻源碼角度講解)
-
jsx和Fiber有什么關(guān)系
答:mount時通過jsx對象(調(diào)用createElement的結(jié)果)調(diào)用createFiberFromElement生成Fiber
update時通過reconcileChildFibers或reconcileChildrenArray對比新jsx和老的Fiber(current Fiber)生成新的wip Fiber樹 -
react17之前jsx文件為什么要聲明import React from 'react'臼予,之后為什么不需要了
答:jsx經(jīng)過編譯之后編程React.createElement,不引入React就會報錯啃沪,react17改變了編譯方式粘拾,變成了jsx.createElement
function App() { return <h1>Hello World</h1>; } //轉(zhuǎn)換后 import {jsx as _jsx} from 'react/jsx-runtime'; function App() { return _jsx('h1', { children: 'Hello world' }); }
-
Fiber是什么,它為什么能提高性能
答:Fiber是一個js對象创千,能承載節(jié)點信息缰雇、優(yōu)先級、updateQueue追驴,同時它還是一個工作單元械哟。
- Fiber雙緩存可以在構(gòu)建好wip Fiber樹之后切換成current Fiber,內(nèi)存中直接一次性切換殿雪,提高了性能
- Fiber的存在使異步可中斷的更新成為了可能暇咆,作為工作單元,可以在時間片內(nèi)執(zhí)行工作,沒時間了交還執(zhí)行權(quán)給瀏覽器糯崎,下次時間片繼續(xù)執(zhí)行之前暫停之后返回的Fiber
- Fiber可以在reconcile的時候進行相應(yīng)的diff更新几缭,讓最后的更新應(yīng)用在真實節(jié)點上
hooks
-
為什么hooks不能寫在條件判斷中
答:hook會按順序存儲在鏈表中,如果寫在條件判斷中沃呢,就沒法保持鏈表的順序
狀態(tài)/生命周期
-
setState是同步的還是異步的
答:legacy模式下:命中batchedUpdates時是異步 未命中batchedUpdates時是同步的
concurrent模式下:都是異步的
-
componentWillMount年栓、componentWillMount、componentWillUpdate為什么標記UNSAFE
答:新的Fiber架構(gòu)能在scheduler的調(diào)度下實現(xiàn)暫停繼續(xù)薄霜,排列優(yōu)先級某抓,Lane模型能使Fiber節(jié)點具有優(yōu)先級,在高優(yōu)先級的任務(wù)打斷低優(yōu)先級的任務(wù)時惰瓜,低優(yōu)先級的更新可能會被跳過否副,所有以上生命周期可能會被執(zhí)行多次,和之前版本的行為不一致崎坊。
組件
-
react元素$$typeof屬性什么
答:用來表示元素的類型备禀,是一個symbol類型
-
react怎么區(qū)分Class組件和Function組件
答:Class組件prototype上有isReactComponent屬性
-
函數(shù)組件和類組件的相同點和不同點
答:相同點:都可以接收props返回react元素
不同點:
編程思想:類組件需要創(chuàng)建實例,面向?qū)ο竽巫幔瘮?shù)組件不需要創(chuàng)建實例曲尸,接收輸入,返回輸出男翰,函數(shù)式編程
內(nèi)存占用:類組建需要創(chuàng)建并保存實例另患,占用一定的內(nèi)存
值捕獲特性:函數(shù)組件具有值捕獲的特性 下面的函數(shù)組件換成類組件打印的num一樣嗎
export default function App() { const [num, setNum] = useState(0); const click = () => { setTimeout(() => { console.log(num); }, 3000); setNum(num + 1); }; return <div onClick={click}>click {num}</div>; } export default class App extends React.Component { state = { num: 0 }; click = () => { setTimeout(() => { console.log(this.state.num); }, 3000); this.setState({ num: this.state.num + 1 }); }; render() { return <div onClick={this.click}>click {this.state.num}</div>; } }
可測試性:函數(shù)組件方便測試
狀態(tài):類組件有自己的狀態(tài),函數(shù)組件沒有只能通過useState
生命周期:類組件有完整生命周期蛾绎,函數(shù)組件沒有可以使用useEffect實現(xiàn)類似的生命周期
邏輯復(fù)用:類組件繼承 Hoc(邏輯混亂 嵌套)昆箕,組合優(yōu)于繼承,函數(shù)組件hook邏輯復(fù)用
跳過更新:shouldComponentUpdate PureComponent租冠,React.memo
發(fā)展未來:函數(shù)組件將成為主流鹏倘,屏蔽this、規(guī)范顽爹、復(fù)用第股,適合時間分片和渲染
開放性問題
-
說說你對react的理解/請說一下react的渲染過程
答:是什么:react是構(gòu)建用戶界面的js庫
能干什么:可以用組件化的方式構(gòu)建快速響應(yīng)的web應(yīng)用程序
如何干:聲明式(jsx) 組件化(方便拆分和復(fù)用 高內(nèi)聚 低耦合) 一次學(xué)習(xí)隨處編寫
做的怎么樣: 優(yōu)缺(社區(qū)繁榮 一次學(xué)習(xí)隨處編寫 api簡介)缺點(沒有系統(tǒng)解決方案 選型成本高 過于靈活)
設(shè)計理念:跨平臺(虛擬dom) 快速響應(yīng)(異步可中斷 增量更新)
性能瓶頸:cpu io fiber時間片 concurrent mode
渲染過程:scheduler render commit Fiber架構(gòu)
聊聊react生命周期
詳見第11章簡述diff算法
詳見第9章-
react有哪些優(yōu)化手段
答:shouldComponentUpdate、不可變數(shù)據(jù)結(jié)構(gòu)话原、列表key夕吻、pureComponent、react.memo繁仁、useEffect依賴項涉馅、useCallback、useMemo黄虱、bailoutOnAlreadyFinishedWork ...
-
react為什么引入jsx
答:jsx聲明式 虛擬dom跨平臺
解釋概念:jsx是js語法的擴展 可以很好的描述ui jsx是React.createElement的語法糖
想實現(xiàn)什么目的:聲明式 代碼結(jié)構(gòu)簡潔 可讀性強 結(jié)構(gòu)樣式和事件可以實現(xiàn)高內(nèi)聚 低耦合 稚矿、復(fù)用和組合 不需要引入新的概念和語法 只寫js, 虛擬dom跨平
有哪些可選方案:模版語法 vue ag引入了控制器 作用域 服務(wù)等概念
jsx原理:babel抽象語法樹 classic是老的轉(zhuǎn)換 automatic新的轉(zhuǎn)換
-
說說virtual Dom的理解
答:是什么:React.createElement函數(shù)返回的就是虛擬dom,用js對象描述真實dom的js對象
優(yōu)點:處理了瀏覽器的兼容性 防范xss攻擊 跨平臺 差異化更新 減少更新的dom操作
缺點:額外的內(nèi)存 初次渲染不一定快
-
你對合成事件的理解
類型 原生事件 合成事件 命名方式 全小寫 小駝峰 事件處理函數(shù) 字符串 函數(shù)對象 阻止默認行為 返回false event.preventDefault() 理解:
- React把事件委托到document上(v17是container節(jié)點上)
- 先處理原生事件 冒泡到document上在處理react事件
- React事件綁定發(fā)生在reconcile階段 會在原生事件綁定前執(zhí)行
優(yōu)勢:
- 進行了瀏覽器兼容晤揣。頂層事件代理桥爽,能保證冒泡一致性(混合使用會出現(xiàn)混亂)
- 默認批量更新
- 避免事件對象頻繁創(chuàng)建和回收,react引入事件池昧识,在事件池中獲取和釋放對象(react17中廢棄)
react17事件綁定在容器上了
- 我們寫的事件是綁定在
dom
上么钠四,如果不是綁定在哪里?
答:v16綁定在document上跪楞,v17綁定在container上 - 為什么我們的事件手動綁定
this
(不是箭頭函數(shù)的情況)
答:合成事件監(jiān)聽函數(shù)在執(zhí)行的時候會丟失上下文 - 為什么不能用
return false
來阻止事件的默認行為缀去?
答:說到底還是合成事件和原生事件觸發(fā)時機不一樣 -
react
怎么通過dom
元素,找到與之對應(yīng)的fiber
對象的甸祭?
答:通過internalInstanceKey對應(yīng)
react源碼18.2
解釋結(jié)果和現(xiàn)象
-
點擊Father組件的div缕碎,Child會打印Child嗎
function Child() { console.log('Child'); return <div>Child</div>; } function Father(props) { const [num, setNum] = React.useState(0); return ( <div onClick={() => {setNum(num + 1)}}> {num} {props.children} </div> ); } function App() { return ( <Father> <Child/> </Father> ); } const rootEl = document.querySelector("#root"); ReactDOM.render(<App/>, rootEl);
答: 不會,源碼中是否命中bailoutOnAlreadyFinishedWork
-
打印順序是什么
function Child() { useEffect(() => { console.log('Child'); }, []) return <h1>child</h1>; } function Father() { useEffect(() => { console.log('Father'); }, []) return <Child/>; } function App() { useEffect(() => { console.log('App'); }, []) return <Father/>; }
答:Child 池户,F(xiàn)ather 咏雌,App ,render階段mount時深度優(yōu)先遍歷校焦,commit階段useEffect執(zhí)行時機
-
useLayout/componentDidMount和useEffect的區(qū)別是什么
class App extends React.Component { componentDidMount() { console.log('mount'); } } useEffect(() => { console.log('useEffect'); }, [])
答:他們在commit階段不同時機執(zhí)行处嫌,useEffect在commit階段結(jié)尾異步調(diào)用,useLayout/componentDidMount同步調(diào)用
![react源碼20.1](https://upload-images.jianshu.io/upload_images/25882458-4dc6ac1da89812b9.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
-
如何解釋demo_4斟湃、demo_8、demo_9出現(xiàn)的現(xiàn)象
答:demo_4:useEffect和useLayoutEffect的區(qū)別
demo_8:任務(wù)的優(yōu)先級有關(guān)檐薯,見源碼分析視頻
demo_9:批量更新有關(guān)凝赛,見源碼分析視頻