網(wǎng)站首頁 編程語言 正文
問題:setState 到底是同步還是異步的?
如果對 React 底層有一定了解,可以回答出 batchUpdate 批量更新概念,以及批量更新被打破的條件。
答案:有時(shí)是同步,有時(shí)是異步。
在 合成事件 和 生命周期函數(shù) 里是 異步 的在 原生事件 和 setTimeout、promise
里是 同步 的
造成setState
的異步并不是由內(nèi)部的異步代碼引起的,在本身的執(zhí)行過程中時(shí)同步的,但是合成事件和生命周期函數(shù)的調(diào)用順序在更新之前,導(dǎo)致在內(nèi)部不能直接得到更新后的值,可以用第二個(gè)參數(shù) callback 來獲取。
具體解釋:可參考setState的執(zhí)行過程
類組件state
setState(obj,callback)
- 第一個(gè)參數(shù):當(dāng) obj 為一個(gè)對象,則為即將合并的 state ;如果 obj 是一個(gè)函數(shù),那么當(dāng)前組件的 state 和 props 將作為參數(shù),返回值用于合并新的 state。
- 第二個(gè)參數(shù) callback :callback 為一個(gè)函數(shù),函數(shù)執(zhí)行上下文中可以獲取當(dāng)前 setState 更新后的最新 state 的值,可以作為依賴 state 變化的副作用函數(shù),可以用來做一些基于 DOM 的操作。
一次事件中觸發(fā)一次如上 setState ,在 React 底層執(zhí)行過程:
render 階段 render 函數(shù)執(zhí)行 -> commit 階段真實(shí) DOM 替換 -> setState 回調(diào)函數(shù)執(zhí)行 callback
首先,setState 會(huì)產(chǎn)生當(dāng)前更新的優(yōu)先級(jí)(老版本用 expirationTime ,新版本用 lane )。接下來 React 會(huì)從 fiber Root 根部 fiber 向下調(diào)和子節(jié)點(diǎn),調(diào)和階段將對比發(fā)生更新的地方,更新對比 expirationTime ,找到發(fā)生更新的組件,合并 state,然后觸發(fā) render 函數(shù),得到新的 UI 視圖層,完成 render 階段。接下來到 commit 階段,commit 階段,替換真實(shí) DOM ,完成此次更新流程。此時(shí)仍然在 commit 階段,會(huì)執(zhí)行 setState 中 callback 函數(shù),到此為止完成了一次 setState 全過程。
setState原理揭秘
本質(zhì):React 底層調(diào)用 Updater 對象上的 enqueueSetState 方法
enqueueSetState()
:創(chuàng)建一個(gè)update,放入當(dāng)前 fiber對象 的待更新隊(duì)列中,最后開啟調(diào)度更新,進(jìn)入更新流程。
React 的 batchUpdate 批量更新
目的:多次 setstate 會(huì)讓邏輯多停留在 js 運(yùn)行層面,阻塞了瀏覽器繪制,因此需要批量更新
batchedEventUpdates ()
:
分析流程:
- React 事件執(zhí)行前通過?isBatchingEventUpdates=true?打開開關(guān),開啟事件批量更新
- 當(dāng)事件結(jié)束,通過?isBatchingEventUpdates=false?關(guān)閉開關(guān)
- 在?scheduleUpdateOnFiber?中根據(jù)這個(gè)開關(guān)來確定是否進(jìn)行批量更新
1)異步環(huán)境下,繼續(xù)開啟批量更新模式:
異步操作里面的批量更新規(guī)則會(huì)被打破,因此提供了手動(dòng)批量更新方法: unstable_batchedUpdates
2)提升更新優(yōu)先級(jí):
提供了方法: flushSync
,可以將回調(diào)函數(shù)中的更新任務(wù),放在一個(gè)較高的優(yōu)先級(jí)中優(yōu)先執(zhí)行
補(bǔ)充:flushSync 在同步條件下,會(huì)合并之前的 setState | useState
3)總結(jié):React 同一級(jí)別更新優(yōu)先級(jí) 關(guān)系是:
flushSync 中的 setState > 正常執(zhí)行上下文中 setState > 異步 setTimeout ,Promise 中的 setState
函數(shù)組件state
const [ state , dispatch ] = useState(initData)
- ① state 目的提供給 UI ,作為渲染視圖的數(shù)據(jù)源
- ② dispatch 改變 state 的函數(shù),可以理解為推動(dòng)函數(shù)組件渲染的渲染函數(shù)
- ③ initData 初始值
initData的初始值
- 第一種情況是非函數(shù),將作為 state 初始化的值
- 第二種情況是函數(shù),函數(shù)的返回值作為 useState 初始化的值
dispatch的參數(shù)
- 第一種非函數(shù)情況,此時(shí)將作為新的值,賦予給 state,作為下一次渲染使用
- 第二種是函數(shù)的情況,如果 dispatch 的參數(shù)為一個(gè)函數(shù),這里可以稱它為reducer,reducer 參數(shù),是上一次返回最新的 state,返回值作為新的 state
監(jiān)聽 state 變化
useEffect
:??梢园?state 作為 依賴項(xiàng) 傳入 useEffect 第二個(gè)參數(shù) deps ,但是注意 useEffect 初始化會(huì)默認(rèn)執(zhí)行一次
dispatch
更新特點(diǎn)
與類組件一樣,但是當(dāng)調(diào)用改變 state 的函數(shù)dispatch,在本次函數(shù)執(zhí)行上下文中,是獲取不到最新的 state 值的
原因:函數(shù)組件更新就是函數(shù)的執(zhí)行,在一次執(zhí)行過程中,函數(shù)內(nèi)部所有變量重新聲明,所以改變的 state 只有在下一次函數(shù)執(zhí)行時(shí)才更新。
useState 原理在之后 Hooks 講解
問:類組件中的 setState
和函數(shù)組件中的 useState
有什么異同?
答:相同點(diǎn):
- 原理:setState 和 useState 更新視圖,底層都調(diào)用了 scheduleUpdateOnFiber 方法,而且事件驅(qū)動(dòng)情況下都有批量更新規(guī)則
- 語法:第一個(gè)參數(shù)都可以傳入函數(shù)
不同點(diǎn):
- 在不是 pureComponent 組件模式下, setState 不會(huì)淺比較兩次 state 的值。只要調(diào)用 setState 就會(huì)執(zhí)行更新。但是 useState 中 dispatchAction 會(huì)默認(rèn)比較兩次state是否相同來更新組件
- setState 有專門監(jiān)聽 state 變化的回調(diào)函數(shù) callback,可以獲取最新 state。但是 useState 只能通過 useEffect 來執(zhí)行 state 變化引起的副作用
- setState 在底層處理邏輯時(shí)將舊 state 進(jìn)行合并處理,而 useState 是重新賦值
原文鏈接:https://blog.csdn.net/weixin_45654582/article/details/121237439
相關(guān)推薦
- 2022-06-12 PostgreSQL數(shù)據(jù)庫事務(wù)插入刪除及更新操作示例_PostgreSQL
- 2022-06-28 C語言簡明講解預(yù)編譯的使用_C 語言
- 2022-04-25 C#使用Npoi導(dǎo)出Excel并合并行列_C#教程
- 2023-12-08 maven中mybatis-generator插件執(zhí)行報(bào)錯(cuò):Cannot resolve class
- 2022-04-28 深入淺出理解C語言指針的綜合應(yīng)用_C 語言
- 2022-04-16 pycharm實(shí)現(xiàn)設(shè)置自動(dòng)的參數(shù)注釋標(biāo)識(shí)_python
- 2022-09-24 pandas刪除某行或某列數(shù)據(jù)的實(shí)現(xiàn)示例_python
- 2022-04-12 【debug】error: no matching function for call to ‘ma
- 最近更新
-
- window11 系統(tǒng)安裝 yarn
- 超詳細(xì)win安裝深度學(xué)習(xí)環(huán)境2025年最新版(
- Linux 中運(yùn)行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲(chǔ)小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎(chǔ)操作-- 運(yùn)算符,流程控制 Flo
- 1. Int 和Integer 的區(qū)別,Jav
- spring @retryable不生效的一種
- Spring Security之認(rèn)證信息的處理
- Spring Security之認(rèn)證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權(quán)
- redisson分布式鎖中waittime的設(shè)
- maven:解決release錯(cuò)誤:Artif
- restTemplate使用總結(jié)
- Spring Security之安全異常處理
- MybatisPlus優(yōu)雅實(shí)現(xiàn)加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務(wù)發(fā)現(xiàn)-Nac
- Spring Security之基于HttpR
- Redis 底層數(shù)據(jù)結(jié)構(gòu)-簡單動(dòng)態(tài)字符串(SD
- arthas操作spring被代理目標(biāo)對象命令
- Spring中的單例模式應(yīng)用詳解
- 聊聊消息隊(duì)列,發(fā)送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠(yuǎn)程分支