深入理解React?State?原理
問題:setState 到底是同步還是異步的?
如果對 React 底層有一定了解,可以回答出 batchUpdate 批量更新概念,以及批量更新被打破的條件。
答案:有時是同步,有時是異步。
在 合成事件 和 生命周期函數(shù) 里是 異步 的在 原生事件 和 setTimeout、promise
里是 同步 的
造成setState
的異步并不是由內(nèi)部的異步代碼引起的,在本身的執(zhí)行過程中時同步的,但是合成事件和生命周期函數(shù)的調(diào)用順序在更新之前,導(dǎo)致在內(nèi)部不能直接得到更新后的值,可以用第二個參數(shù) callback 來獲取。
具體解釋:可參考setState的執(zhí)行過程
類組件state
setState(obj,callback)
- 第一個參數(shù):當(dāng) obj 為一個對象,則為即將合并的 state ;如果 obj 是一個函數(shù),那么當(dāng)前組件的 state 和 props 將作為參數(shù),返回值用于合并新的 state。
- 第二個參數(shù) callback :callback 為一個函數(shù),函數(shù)執(zhí)行上下文中可以獲取當(dāng)前 setState 更新后的最新 state 的值,可以作為依賴 state 變化的副作用函數(shù),可以用來做一些基于 DOM 的操作。
一次事件中觸發(fā)一次如上 setState ,在 React 底層執(zhí)行過程:
render 階段 render 函數(shù)執(zhí)行 -> commit 階段真實 DOM 替換 -> setState 回調(diào)函數(shù)執(zhí)行 callback
首先,setState 會產(chǎn)生當(dāng)前更新的優(yōu)先級(老版本用 expirationTime ,新版本用 lane )。接下來 React 會從 fiber Root 根部 fiber 向下調(diào)和子節(jié)點,調(diào)和階段將對比發(fā)生更新的地方,更新對比 expirationTime ,找到發(fā)生更新的組件,合并 state,然后觸發(fā) render 函數(shù),得到新的 UI 視圖層,完成 render 階段。接下來到 commit 階段,commit 階段,替換真實 DOM ,完成此次更新流程。此時仍然在 commit 階段,會執(zhí)行 setState 中 callback 函數(shù),到此為止完成了一次 setState 全過程。
setState原理揭秘
本質(zhì):React 底層調(diào)用 Updater 對象上的 enqueueSetState 方法
enqueueSetState()
:創(chuàng)建一個update,放入當(dāng)前 fiber對象 的待更新隊列中,最后開啟調(diào)度更新,進(jìn)入更新流程。
React 的 batchUpdate 批量更新
目的:多次 setstate 會讓邏輯多停留在 js 運行層面,阻塞了瀏覽器繪制,因此需要批量更新
batchedEventUpdates ()
:
分析流程:
- React 事件執(zhí)行前通過 isBatchingEventUpdates=true 打開開關(guān),開啟事件批量更新
- 當(dāng)事件結(jié)束,通過 isBatchingEventUpdates=false 關(guān)閉開關(guān)
- 在 scheduleUpdateOnFiber 中根據(jù)這個開關(guān)來確定是否進(jìn)行批量更新
1)異步環(huán)境下,繼續(xù)開啟批量更新模式:
異步操作里面的批量更新規(guī)則會被打破,因此提供了手動批量更新方法: unstable_batchedUpdates
2)提升更新優(yōu)先級:
提供了方法: flushSync
,可以將回調(diào)函數(shù)中的更新任務(wù),放在一個較高的優(yōu)先級中優(yōu)先執(zhí)行
補充:flushSync 在同步條件下,會合并之前的 setState | useState
3)總結(jié):React 同一級別更新優(yōu)先級 關(guān)系是:
flushSync 中的 setState > 正常執(zhí)行上下文中 setState > 異步 setTimeout ,Promise 中的 setState
函數(shù)組件state
const [ state , dispatch ] = useState(initData)
- ① state 目的提供給 UI ,作為渲染視圖的數(shù)據(jù)源
- ② dispatch 改變 state 的函數(shù),可以理解為推動函數(shù)組件渲染的渲染函數(shù)
- ③ initData 初始值
initData的初始值
- 第一種情況是非函數(shù),將作為 state 初始化的值
- 第二種情況是函數(shù),函數(shù)的返回值作為 useState 初始化的值
dispatch的參數(shù)
- 第一種非函數(shù)情況,此時將作為新的值,賦予給 state,作為下一次渲染使用
- 第二種是函數(shù)的情況,如果 dispatch 的參數(shù)為一個函數(shù),這里可以稱它為reducer,reducer 參數(shù),是上一次返回最新的 state,返回值作為新的 state
監(jiān)聽 state 變化
useEffect
:常可以把 state 作為 依賴項 傳入 useEffect 第二個參數(shù) deps ,但是注意 useEffect 初始化會默認(rèn)執(zhí)行一次
dispatch
更新特點
與類組件一樣,但是當(dāng)調(diào)用改變 state 的函數(shù)dispatch,在本次函數(shù)執(zhí)行上下文中,是獲取不到最新的 state 值的
原因:函數(shù)組件更新就是函數(shù)的執(zhí)行,在一次執(zhí)行過程中,函數(shù)內(nèi)部所有變量重新聲明,所以改變的 state 只有在下一次函數(shù)執(zhí)行時才更新。
useState 原理在之后 Hooks 講解
問:類組件中的 setState
和函數(shù)組件中的 useState
有什么異同?
答:相同點:
- 原理:setState 和 useState 更新視圖,底層都調(diào)用了 scheduleUpdateOnFiber 方法,而且事件驅(qū)動情況下都有批量更新規(guī)則
- 語法:第一個參數(shù)都可以傳入函數(shù)
不同點:
- 在不是 pureComponent 組件模式下, setState 不會淺比較兩次 state 的值。只要調(diào)用 setState 就會執(zhí)行更新。但是 useState 中 dispatchAction 會默認(rèn)比較兩次state是否相同來更新組件
- setState 有專門監(jiān)聽 state 變化的回調(diào)函數(shù) callback,可以獲取最新 state。但是 useState 只能通過 useEffect 來執(zhí)行 state 變化引起的副作用
- setState 在底層處理邏輯時將舊 state 進(jìn)行合并處理,而 useState 是重新賦值
到此這篇關(guān)于深入理解React State 原理的文章就介紹到這了,更多相關(guān)React State 原理 內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
封裝一個最簡單ErrorBoundary組件處理react異常
這篇文章主要介紹了一個處理react異常的ErrorBoundary組件,簡單實用,代碼詳細(xì),對這個組件感興趣的朋友可以參考下2021-04-04React中hook函數(shù)與useState及useEffect的使用
這篇文章主要介紹了React中hook函數(shù)與useState及useEffect的使用,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)吧2022-10-10詳解如何使用React Hooks請求數(shù)據(jù)并渲染
這篇文章主要介紹了如何使用React Hooks請求數(shù)據(jù)并渲染,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-10-10詳解如何用webpack4從零開始構(gòu)建react開發(fā)環(huán)境
這篇文章主要介紹了詳解如何用webpack4從零開始構(gòu)建react開發(fā)環(huán)境,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2019-01-01react同構(gòu)實踐之實現(xiàn)自己的同構(gòu)模板
這篇文章主要介紹了react同構(gòu)實踐之實現(xiàn)自己的同構(gòu)模板,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-03-03