最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

深度解析React18 flushSync的使用

 更新時間:2026年06月18日 10:18:01   作者:英俊瀟灑美少年  
React18的flushSync API用于強(qiáng)制同步執(zhí)行狀態(tài)更新和DOM渲染,跳過React的并發(fā)調(diào)度和批處理機(jī)制,文章全面解析了flushSync的核心作用、基礎(chǔ)用法、適用場景和禁止使用場景,感興趣的可以了解一下

前言

React18 引入了并發(fā)渲染與全局自動批處理,默認(rèn)情況下所有setState都會異步合并渲染優(yōu)化性能。但部分業(yè)務(wù)需要修改狀態(tài)后立刻拿到最新DOM,官方提供了flushSync強(qiáng)制同步刷新API。本文覆蓋所有執(zhí)行場景、陷阱、優(yōu)先級、異常、對比、面試題

導(dǎo)入方式:import { flushSync } from 'react-dom'

一、基礎(chǔ)介紹

1. 核心作用

強(qiáng)制同步執(zhí)行回調(diào)內(nèi)狀態(tài)更新,跳過并發(fā)調(diào)度、批處理機(jī)制,同步走完render → commit → DOM真實更新全流程。

2. 基礎(chǔ)示例

const [count, setCount] = useState(0)
const handle = () => {
  flushSync(() => {
    setCount(1)
  })
  // 此處DOM已經(jīng)刷新完成,可讀取offset、焦點等
}

3. 適用場景

  1. 修改狀態(tài)后立即讀取DOM寬高、位置、滾動距離
  2. 渲染完成馬上控制輸入框焦點
  3. 對接圖表、動畫等第三方庫,必須依賴最新DOM實例
  4. 多步驟邏輯強(qiáng)依賴上一步渲染結(jié)果

4. 禁止使用場景

  1. 組件渲染函數(shù)體內(nèi)直接調(diào)用
  2. useEffect、useLayoutEffect內(nèi)部調(diào)用(會控制臺警告)
  3. 無必要場景濫用,會破壞并發(fā)渲染、降低頁面性能

二、全場景執(zhí)行邏輯拆解

場景1:flushSync前置存在普通setState

規(guī)則

執(zhí)行flushSync時,會優(yōu)先清空之前所有堆積未渲染的更新隊列,前置更新單獨渲染一次,內(nèi)部更新合并再渲染一次。

const [n, setN] = useState(0)
const run = () => {
  setN(1) // 緩存入隊,暫不渲染
  flushSync(() => {
    setN(prev => prev + 2)
  })
  console.log(n) // 輸出3
}

執(zhí)行流程:

  1. setN(1)進(jìn)入待更新隊列
  2. 進(jìn)入flushSync,先沖刷前置隊列,n=1,第一次同步渲染
  3. 內(nèi)部setN(prev+2)存入同步批次
  4. 回調(diào)執(zhí)行完畢批量渲染,n=3,第二次渲染

場景2:flushSync內(nèi)部多個setState

規(guī)則

同一個flushSync回調(diào)內(nèi)多個狀態(tài)更新,自動合并批量,只同步渲染1次。區(qū)別普通更新:普通是異步批處理,這里是同步批處理。

flushSync(() => {
  setCount(1)
  setName('demo')
  setVisible(true)
})
// 三個狀態(tài)一次性同步更新DOM,僅渲染一次

場景3:flushSync嵌套調(diào)用

底層鐵律

同一時間只能存在一個同步刷新上下文;同步棧內(nèi)嵌套的flushSync直接失效,僅執(zhí)行回調(diào),不會新增渲染次數(shù)。

flushSync(() => {
  setCount(p => p + 1)
  // 內(nèi)層全部失效,無獨立刷新
  flushSync(() => {
    setCount(p => p + 2)
    flushSync(() => setCount(p => p + 3))
  })
})
// 總計只渲染1次,最終count=6

嵌套問題解決方案

想要分步多次同步刷新,禁止嵌套,拆分為平級獨立flushSync

flushSync(() => setA(1)) // 第一次渲染
flushSync(() => setB(2)) // 第二次渲染
flushSync(() => setC(3)) // 第三次渲染

場景4:flushSync內(nèi)部包含異步代碼(async/await/setTimeout/Promise)

核心結(jié)論

只有同步執(zhí)行棧內(nèi)的setState受flushSync管控;一旦進(jìn)入異步回調(diào)(定時器、then、await后),狀態(tài)更新脫離同步上下文,回歸默認(rèn)異步批處理。

  1. setTimeout宏任務(wù)示例
flushSync(() => {
  setNum(1)
  setTimeout(() => {
    setNum(2) // 異步隊列,延遲渲染,不跟隨同步刷新
  }, 0)
})
// 外層DOM先變?yōu)?,宏任務(wù)執(zhí)行后才變?yōu)?
  1. async/await陷阱(極易踩坑)
const fn = async () => {
  flushSync(async () => {
    setN(1)
    await Promise.resolve() // 讓出同步棧,后續(xù)代碼變成微任務(wù)
    setN(2) // 不受flushSync管控,異步渲染
  })
}
  1. 異步回調(diào)內(nèi)新開flushSync
    異步執(zhí)行棧中創(chuàng)建的flushSync是全新獨立同步上下文,可以正常強(qiáng)制刷新:
flushSync(() => {
  setNum(1)
  setTimeout(() => {
    flushSync(() => setNum(2)) // 獨立生效,同步渲染
  }, 0)
})

場景5:flushSync內(nèi)部拋出異常

規(guī)則

回調(diào)內(nèi)報錯不會回滾已執(zhí)行的狀態(tài)更新,已經(jīng)執(zhí)行的setState依舊會同步渲染;錯誤同步拋出,可用try/catch捕獲。

const [n, setN] = useState(0)
const test = () => {
  try {
    flushSync(() => {
      setN(1) // 正常渲染生效
      throw new Error('執(zhí)行異常')
      setN(2) // 不會執(zhí)行
    })
  } catch (err) {}
  console.log(n) // 打印1
}

場景6:flushSync搭配startTransition(優(yōu)先級對比)

優(yōu)先級排序:flushSync(最高同步) > 普通更新 > startTransition(低優(yōu)先級過渡)
flushSync會插隊優(yōu)先執(zhí)行,transition內(nèi)更新延后渲染:

const [n, setN] = useState(0)
const run = () => {
  startTransition(() => setN(10)) // 低優(yōu)先級延后
  flushSync(() => setN(1)) // 最高優(yōu)先級立刻渲染
  console.log(n) // 打印1
}

場景7:useLayoutEffect / useEffect中調(diào)用flushSync

渲染周期鉤子內(nèi)部調(diào)用會觸發(fā)React警告,屬于不規(guī)范寫法。渲染階段本身正在執(zhí)行更新流程,無法二次開啟同步刷新上下文。

// 警告不推薦
useLayoutEffect(() => {
  flushSync(() => setCount(1))
}, [])

場景8:實戰(zhàn)標(biāo)準(zhǔn)DOM讀取場景

業(yè)務(wù)最常用:先展示隱藏元素,立刻讀取尺寸計算動畫、定位:

const boxRef = useRef(null)
const openBox = () => {
  flushSync(() => setShow(true))
  // DOM已渲染完成,精準(zhǔn)獲取高度
  const height = boxRef.current.offsetHeight
}

三、經(jīng)典閉包快照陷阱

flushSync僅同步DOM視圖,組件內(nèi)state變量為函數(shù)執(zhí)行瞬間的閉包快照,不會實時變化;狀態(tài)累加務(wù)必使用函數(shù)式更新setX(prev => prev + val)。

const [val, setVal] = useState(0)
const run = () => {
  setVal(1)
  flushSync(() => {
    console.log(val) // 0,閉包捕獲舊快照
    setVal(p => p + 2) // 函數(shù)式更新不受快照影響
  })
}

四、重要注意事項(避坑清單)

  1. 杜絕濫用:強(qiáng)制同步渲染會打斷React并發(fā)機(jī)制,頻繁調(diào)用造成頁面卡頓
  2. 同步棧內(nèi)禁止嵌套,分步刷新只能平級書寫
  3. 不要給flushSync傳遞async回調(diào),await會撕裂同步執(zhí)行棧
  4. 異步邏輯如需同步DOM,在異步回調(diào)內(nèi)部單獨包裹flushSync
  5. 循環(huán)中批量調(diào)用flushSync會產(chǎn)生多次重渲染,性能損耗極大
  6. 遇到Suspense時,flushSync強(qiáng)制同步會直接展示fallback加載態(tài),無法等待異步資源
  7. 狀態(tài)累加統(tǒng)一使用函數(shù)式更新,規(guī)避閉包快照數(shù)值錯誤

五、flushSync vs Vue nextTick 對比

對比項React flushSyncVue nextTick
核心行為主動強(qiáng)制立刻同步刷新DOM被動等待DOM更新完畢再執(zhí)行回調(diào)
執(zhí)行類型同步阻塞代碼微任務(wù)異步執(zhí)行
批處理影響打破React默認(rèn)自動批處理不改變Vue自身批處理邏輯
使用目的修改state馬上拿到最新DOM修改數(shù)據(jù)后等渲染完成操作DOM
兩者關(guān)系邏輯完全相反,不能互相替代邏輯完全相反,不能互相替代

六、高頻面試真題(含完整答案)

面試題1 前置setState+內(nèi)部多更新

const [n, setN] = useState(0);
function handleClick() {
  setN(1);
  flushSync(() => {
    setN(prev => prev + 2);
    setN(prev => prev + 3);
  });
  console.log(n);
}

答案:打印6;總渲染2次(前置1次、內(nèi)部合并1次)

面試題2 同步多層嵌套flushSync

const [num, setNum] = useState(0);
function test() {
  flushSync(() => {
    setNum(1);
    flushSync(() => {
      setNum(2);
      flushSync(() => {
        setNum(3);
      });
    });
  });
  console.log(num);
}

答案:打印3;僅渲染1次,內(nèi)層嵌套全部失效

面試題3 壓軸綜合大題

const [count, setCount] = useState(0);
function handleClick() {
  setCount(1);

  flushSync(() => {
    setCount(p => p + 1);
    flushSync(() => {
      setCount(p => p + 2);
      flushSync(() => {
        setCount(p => p + 3);
      });
    });
  });

  flushSync(() => {
    setCount(p => p + 4);
  });

  console.log(count);
}

問題1:最終打印數(shù)值?問題2:原始代碼渲染幾次?問題3:第二個平級flushSync挪入最深嵌套渲染幾次?
答案:

  1. 1+1+2+3+4 = 11,打印11
  2. 原始渲染3次:前置1次、嵌套批量1次、平級第二個獨立1次
  3. 移入嵌套后全程單同步上下文,僅渲染2次

面試題4 異常場景

const [n, setN] = useState(0);
function test() {
  try {
    flushSync(() => {
      setN(1);
      throw Error('err');
    });
  } catch (e) {}
  console.log(n);
}

答案:打印1,異常不會回滾已執(zhí)行狀態(tài)

面試題5 優(yōu)先級startTransition對比

const [n, setN] = useState(0);
function test() {
  startTransition(() => setN(10));
  flushSync(() => setN(1));
  console.log(n);
}

答案:打印1,flushSync優(yōu)先級高于transition

七、開發(fā)最佳實踐

  1. 優(yōu)先使用useLayoutEffect派生數(shù)據(jù)、操作DOM,非必要不用flushSync
  2. 接口請求、異步邏輯放在flushSync外部,拿到結(jié)果后再同步刷新視圖
  3. 同一批次無關(guān)多狀態(tài)統(tǒng)一放入單個flushSync,減少渲染次數(shù)
  4. 多層分步DOM操作拆分平級flushSync,不依賴嵌套邏輯
  5. 所有數(shù)值疊加更新全部采用函數(shù)式setX(prev => prev + value)寫法

總結(jié)

  1. flushSync為最高優(yōu)先級同步刷新,前置隊列會提前沖刷
  2. 同回調(diào)內(nèi)多setState合并一次渲染;同步棧嵌套內(nèi)層失效
  3. 異步代碼脫離同步上下文,只有異步內(nèi)新開flushSync才可再次同步
  4. 異常、閉包、transition、生命周期均有固定執(zhí)行規(guī)則
  5. 和Vue nextTick行為完全相反,一個強(qiáng)制立刻刷,一個等待刷完再執(zhí)行
  6. 謹(jǐn)慎使用,僅DOM讀取、焦點、第三方庫兼容場景作為兜底方案

到此這篇關(guān)于深度解析React18 flushSync的使用的文章就介紹到這了,更多相關(guān)React18 flushSync內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • JavaScript React如何修改默認(rèn)端口號方法詳解

    JavaScript React如何修改默認(rèn)端口號方法詳解

    這篇文章主要介紹了JavaScript React如何修改默認(rèn)端口號方法詳解,文中通過步驟圖片解析介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-07-07
  • React?Immutable使用方法詳細(xì)介紹

    React?Immutable使用方法詳細(xì)介紹

    Immutable.js出自Facebook,是最流行的不可變數(shù)據(jù)結(jié)構(gòu)的實現(xiàn)之一。它實現(xiàn)了完全的持久化數(shù)據(jù)結(jié)構(gòu),使用結(jié)構(gòu)共享。所有的更新操作都會返回新的值,但是在內(nèi)部結(jié)構(gòu)是共享的,來減少內(nèi)存占用
    2022-09-09
  • 如何解決React useEffect鉤子帶來的無限循環(huán)問題

    如何解決React useEffect鉤子帶來的無限循環(huán)問題

    本文主要介紹了解決React useEffect鉤子帶來的無限循環(huán)問題,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-07-07
  • React項目仿小紅書首頁保姆級實戰(zhàn)教程

    React項目仿小紅書首頁保姆級實戰(zhàn)教程

    React 是一個用于構(gòu)建用戶界面的 Javascript庫,接下來將通過實戰(zhàn)小紅書首頁的詳細(xì)介紹其設(shè)計思路和方法,將讀者帶入到react的開源世界,需要的朋友可以參考下
    2022-07-07
  • 在React中使用SVG的幾種方式

    在React中使用SVG的幾種方式

    在React中,SVG(Scalable?Vector?Graphics)的使用非常普遍,因為它們提供了可伸縮的矢量圖形,這對于現(xiàn)代Web應(yīng)用來說是非常重要的,以下是幾種常見的在React中使用SVG的方法,每種方法都有其特定的用例和最佳實踐,需要的朋友可以參考下
    2024-11-11
  • react-router-domV6版本的路由和嵌套路由寫法詳解

    react-router-domV6版本的路由和嵌套路由寫法詳解

    本文主要介紹了react-router-domV6版本的路由和嵌套路由寫法詳解,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-03-03
  • 深入理解React調(diào)度(Scheduler)原理

    深入理解React調(diào)度(Scheduler)原理

    本文主要介紹了深入理解React調(diào)度(Scheduler)原理,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-07-07
  • 使用React18和WebSocket構(gòu)建實時通信功能詳解

    使用React18和WebSocket構(gòu)建實時通信功能詳解

    WebSocket是一種在Web應(yīng)用中實現(xiàn)雙向通信的協(xié)議,它允許服務(wù)器主動向客戶端推送數(shù)據(jù),而不需要客戶端發(fā)起請求,本文將探索如何在React?18應(yīng)用中使用WebSocket來實現(xiàn)實時通信,感興趣的可以了解下
    2024-01-01
  • React中使用UMEditor的方法示例

    React中使用UMEditor的方法示例

    這篇文章主要介紹了React中使用UMEditor的方法示例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-12-12
  • React和Vue的props驗證示例詳解

    React和Vue的props驗證示例詳解

    這篇文章主要介紹了React和Vue的props驗證,本文通過示例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-08-08

最新評論

栾川县| 科技| 汽车| 宁强县| 牟定县| 盐亭县| 灵台县| 天台县| 专栏| 巴青县| 油尖旺区| 南涧| 余江县| 晋州市| 项城市| 鹤壁市| 东城区| 古蔺县| 湖口县| 克山县| 扎囊县| 长子县| 简阳市| 乐平市| 贵阳市| 竹北市| 博野县| 海城市| 杭锦后旗| 丁青县| 萍乡市| 宜阳县| 宣武区| 眉山市| 静海县| 本溪| 炉霍县| 婺源县| 塔河县| 贺州市| 宁阳县|