中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

React架構的演變之如何理解Hooks的實現

發布時間:2021-10-25 17:08:28 來源:億速云 閱讀:185 作者:iii 欄目:開發技術

本篇內容介紹了“React架構的演變之如何理解Hooks的實現”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!

Hook 如何與組件關聯

在之前的文章中多次提到,Fiber 架構下的 updateQueue、effectList 都是鏈表的數據結構,然后掛載的 Fiber  節點上。而一個函數組件內所有的 Hooks 也是通過鏈表的形式存儲的,最后掛載到 fiber.memoizedState 上。

function App() {   const [num, updateNum] = useState(0)    return <div     onClick={() => updateNum(num => num + 1)}   >{ num }</div> }  export default App

我們先簡單看下,調用 useState 時,構造鏈表的過程:

var workInProgressHook = null var HooksDispatcherOnMount = {   useState: function (initialState) {     return mountState(initialState)   } }  function function mountState(initialState) {   // 新的 Hook 節點   var hook = mountWorkInProgressHook()   // 緩存初始值   hook.memoizedState = initialState   // 構造更新隊列,類似于 fiber.updateQueue   var queue = hook.queue = {     pending: null,     dispatch: null,     lastRenderedState: initialState   }   // 用于派發更新   var dispatch = queue.dispatch = dispatchAction.bind(     null, workInProgress, queue   )   // [num, updateNum] = useState(0)   return [hook.memoizedState, dispatch] }  function mountWorkInProgressHook() {   var hook = {     memoizedState: null,     baseState: null,     baseQueue: null,     queue: null,     next: null   }    if (workInProgressHook === null) {     // 構造鏈表頭節點     workInProgress.memoizedState = workInProgressHook = hook   } else {     // 如果鏈表已經存在,在掛載到 next     workInProgressHook = workInProgressHook.next = hook   }    return workInProgressHook }

React架構的演變之如何理解Hooks的實現

如果此時有兩個 Hook,第二個 Hook 就會掛載到第一個 Hook 的 next 屬性上。

function App() {   const [num, updateNum] = useState(0)   const [str, updateStr] = useState('value: ')    return <div     onClick={() => updateNum(num => num + 1)}   >{ str } { num }</div> }  export default App

React架構的演變之如何理解Hooks的實現

Hook

Hook 的更新隊列

Hook 通過 .next 彼此相連,而每個 Hook 對象下,還有個 queue 字段,該字段和 Fiber 節點上的 updateQueue  一樣,是一個更新隊列在,上篇文章 《React 架構的演變-更新機制》中有講到,React Fiber 架構中,更新隊列通過鏈表結構進行存儲。

class App extends React.Component {   state = { val: 0 }   click () {     for (let i = 0; i < 3; i++) {       this.setState({ val: this.state.val + 1 })     }   }   render() {     return <div onClick={() => {       this.click()     }}>val: { this.state.val }</div>   } }

點擊 div 之后,產生的 3 次 setState 通過鏈表的形式掛載到 fiber.updateQueue 上,待到 MessageChannel  收到通知后,真正執行更新操作時,取出更新隊列,將計算結果更新到 fiber.memoizedState。

React架構的演變之如何理解Hooks的實現

setState

而 hook.queue 的邏輯和 fiber.updateQueue 的邏輯也是完全一致的。

function App() {   const [num, updateNum] = useState(0)    return <div     onClick={() => {       // 連續更新 3 次       updateNum(num => num + 1)       updateNum(num => num + 1)       updateNum(num => num + 1)     }}   >     { num }   </div> }  export default App; var dispatch = queue.dispatch = dispatchAction.bind(   null, workInProgress, queue ) // [num, updateNum] = useState(0) return [hook.memoizedState, dispatch]

調用 useState 的時候,返回的數組第二個參數為 dispatch,而 dispatch 由 dispatchAction bind  后得到。

function dispatchAction(fiber, queue, action) {   var update = {     next: null,     action: action,     // 省略調度相關的參數...   };    var pending = queue.pending   if (pending === null) {     update.next = update   } else {     update.next = pending.next     pending.next = update   }   queue.pending = update    // 執行更新   scheduleUpdateOnFiber() }

可以看到這里構造鏈表的方式與 fiber.updateQueue 如出一轍。之前我們通過 updateNum 對 num 連續更新了 3  次,最后形成的更新隊列如下:

React架構的演變之如何理解Hooks的實現

更新隊列

函數組件的更新

前面的文章分享過,Fiber 架構下的更新流程分為遞(beginWork)、歸(completeWork)兩個步驟,在 beginWork  中,會依據組件類型進行 render 操作構造子組件。

function beginWork(current, workInProgress) {   switch (workInProgress.tag) {     // 其他類型組件代碼省略...     case FunctionComponent: {       // 這里的 type 就是函數組件的函數       // 例如,前面的 App 組件,type 就是 function App() {}       var Component = workInProgress.type       var resolvedProps = workInProgress.pendingProps       // 組件更新       return updateFunctionComponent(         current, workInProgress, Component, resolvedProps       )     }   } }  function updateFunctionComponent(  current, workInProgress, Component, nextProps ) {   // 構造子組件   var nextChildren = renderWithHooks(     current, workInProgress, Component, nextProps   )   reconcileChildren(current, workInProgress, nextChildren)   return workInProgress.child }

看名字就能看出來,renderWithHooks 方法就是構造帶 Hooks 的子組件。

function renderWithHooks(  current, workInProgress, Component, props ) {   if (current !== null && current.memoizedState !== null) {     ReactCurrentDispatcher.current = HooksDispatcherOnUpdate   } else {     ReactCurrentDispatcher.current = HooksDispatcherOnMount   }   var children = Component(props)   return children }

從上面的代碼可以看出,函數組件更新或者首次渲染時,本質就是將函數取出執行了一遍。不同的地方在于給 ReactCurrentDispatcher  進行了不同的賦值,而 ReactCurrentDispatcher 的值最終會影響 useState 調用不同的方法。

根據之前文章講過的雙緩存機制,current 存在的時候表示是更新操作,不存在的時候表示首次渲染。

function useState(initialState) {   // 首次渲染時指向 HooksDispatcherOnMount   // 更新操作時指向 HooksDispatcherOnUpdate   var dispatcher = ReactCurrentDispatcher.current   return dispatcher.useState(initialState) }

HooksDispatcherOnMount.useState 的代碼前面已經介紹過,這里不再著重介紹。

// HooksDispatcherOnMount 的代碼前面已經介紹過 var HooksDispatcherOnMount = {   useState: function (initialState) {     return mountState(initialState)   } }

我們重點看看 HooksDispatcherOnMount.useState 的邏輯。

var HooksDispatcherOnUpdateInDEV = {   useState: function (initialState) {     return updateState()   } }  function updateState() {   // 取出當前 hook   workInProgressHook = nextWorkInProgressHook   nextWorkInProgressHook = workInProgressHook.next    var hook = nextWorkInProgressHook   var queue = hook.queue   var pendingQueue = queue.pending    // 處理更新   var first = pendingQueue.next   var state = hook.memoizedState   var update = first    do {     var action = update.action     state = typeof action === 'function' ? action(state) : action      update = update.next;   } while (update !== null && update !== first)     hook.memoizedState = state    var dispatch = queue.dispatch   return [hook.memoizedState, dispatch] }

如果有看之前的 setState 的代碼,這里的邏輯其實是一樣的。將更新對象的 action 取出,如果是函數就執行,如果不是函數就直接對 state  進行替換操作。

“React架構的演變之如何理解Hooks的實現”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

上杭县| 乌兰县| 保康县| 简阳市| 峨边| 墨江| 连平县| 万宁市| 永嘉县| 汤原县| 会理县| 郯城县| 高邮市| 伊宁市| 大余县| 平江县| 凉山| 平遥县| 雷波县| 城步| 大名县| 锡林郭勒盟| 天等县| 金堂县| 雅江县| 玛曲县| 贵阳市| 巴南区| 黄梅县| 五华县| 盐亭县| 长丰县| 巴彦淖尔市| 辉南县| 天峻县| 潮安县| 邯郸市| 沐川县| 藁城市| 武陟县| 金塔县|