日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問(wèn)題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷解決方案
悄悄告訴你:React18文檔里寫錯(cuò)的地方

大家好,我卡頌

React18正式版已經(jīng)發(fā)布一段時(shí)間了,如果你升級(jí)到v18,且仍使用ReactDOM.render創(chuàng)建應(yīng)用,會(huì)收到如下報(bào)警:

大意是說(shuō):v18使用createRoot而不是render創(chuàng)建應(yīng)用,如果你仍使用render創(chuàng)建應(yīng)用,那么應(yīng)用的行為將同v17一樣。

React團(tuán)隊(duì)之所以有底氣讓大家都升級(jí)到v18,使用createRoot,是因?yàn)樗麄冏鞒隽顺兄Z:

大意是說(shuō):如果你升級(jí)到v18,只要不使用「并發(fā)特性」(比如useTransition),React會(huì)和之前版本表現(xiàn)一致(更新會(huì)同步、不可中斷)。

今天這篇文章想說(shuō)的是:某些情況下,上述說(shuō)法是錯(cuò)誤的。

不說(shuō)廢話,上示例示

例中有a、b兩個(gè)狀態(tài),首次渲染完2秒后會(huì)觸發(fā)a、b更新。

其中觸發(fā)b更新的方式比較特殊:模擬點(diǎn)擊,間接觸發(fā)b更新:

function App() {
const [a, setA] = useState(0);
const [b, setB] = useState(0);
const BtnRef = useRef(null);
useEffect(() => {
setTimeout(() => {
setA(9000);
BtnRef.current?.click();
}, 2000);
}, []);
return (


{Array(a).fill(0).map((_, i) => {
return
{a}
;
})}

);
}

完整示例地址[1]

現(xiàn)在我們有兩種掛載的方式。

v18之前的方式:

const rootElement = document.getElementById("root");
// v18之前創(chuàng)建應(yīng)用的方式
ReactDOM.render(, rootElement);

v18提供的方式:

const root = ReactDOM.createRoot(rootElement);
// v18創(chuàng)建應(yīng)用的方式
root.render(

);

為了看清這兩者的區(qū)別,有兩種方式:

調(diào)大setA(9000)中的值,使頁(yè)面渲染更多項(xiàng)。頁(yè)面渲染時(shí)卡頓越明顯,渲染順序的差異越明顯。

setTimeout(() => {
setA(9000);
BtnRef.current?.click();
}, 2000);

在react-dom.development.js的commitRootImpl方法中打斷點(diǎn)。

這個(gè)方法是React渲染時(shí)調(diào)用的方法,在這里打斷點(diǎn)可以看出頁(yè)面渲染的順序。

對(duì)于ReactDOM.render創(chuàng)建的應(yīng)用,觸發(fā)更新后渲染順序如下:

首先:

其次:

對(duì)于ReactDOM.createRoot創(chuàng)建的應(yīng)用,觸發(fā)更新后渲染順序如下:

首先:

其次:

渲染順序顯然是變了,這和React文檔里的說(shuō)法是相悖的。

背后的原因是什么呢?

更新的優(yōu)先級(jí),無(wú)處不在

先解釋下示例中的b為什么采用「觸發(fā)onClick事件」的方式間接觸發(fā)更新:

BtnRef.current?.click();

這是因?yàn)椋翰煌绞接|發(fā)的更新有不同「優(yōu)先級(jí)」,onClick回調(diào)中觸發(fā)的更新是最高優(yōu)的,即「同步優(yōu)先級(jí)」。

那么問(wèn)題來(lái)了,v18不使用并發(fā)特性,所有更新不都該是「同步、不可中斷」么?

這話是沒(méi)錯(cuò),更新本身是「同步、不可中斷」的。但是更新是需要調(diào)度的。

在示例中,如果采用ReactDOM.createRoot創(chuàng)建應(yīng)用,那么觸發(fā)更新時(shí)的優(yōu)先級(jí)如下:

setTimeout(() => {
// 觸發(fā)更新,優(yōu)先級(jí)為“默認(rèn)優(yōu)先級(jí)”
setA(9000);
// 觸發(fā)更新,優(yōu)先級(jí)為“同步優(yōu)先級(jí)”
BtnRef.current?.click();
}, 2000);

接下來(lái)React的執(zhí)行流程如下:

  1. a觸發(fā)更新,優(yōu)先級(jí)為“默認(rèn)優(yōu)先級(jí)”。
  2. 調(diào)度a的更新,優(yōu)先級(jí)為“默認(rèn)優(yōu)先級(jí)”。
  3. b觸發(fā)更新,優(yōu)先級(jí)為“同步優(yōu)先級(jí)”。
  4. 調(diào)度b的更新,優(yōu)先級(jí)為“同步優(yōu)先級(jí)”。
  5. 此時(shí)發(fā)現(xiàn)已經(jīng)有個(gè)更新在調(diào)度(a的更新),且優(yōu)先級(jí)更低(默認(rèn)優(yōu)先級(jí) < 同步優(yōu)先級(jí))。
  6. 取消a的更新的調(diào)度,轉(zhuǎn)而開(kāi)始調(diào)度b的更新。
  7. 調(diào)度流程結(jié)束,開(kāi)始同步、不可中斷的執(zhí)行b的更新。
  8. b對(duì)應(yīng)更新渲染到頁(yè)面中。
  9. 此時(shí)發(fā)現(xiàn)還有一個(gè)更新(a的更新),調(diào)度他。
  10. 調(diào)度流程結(jié)束,開(kāi)始同步、不可中斷的執(zhí)行a的更新。
  11. a對(duì)應(yīng)更新渲染到頁(yè)面中。

可見(jiàn),只要采用ReactDOM.createRoot創(chuàng)建應(yīng)用,那么「優(yōu)先級(jí)」的影響就會(huì)一直存在,與「使用了并發(fā)特性」的區(qū)別是:

  • 只有「默認(rèn)優(yōu)先級(jí)」與「同步優(yōu)先級(jí)」。
  • 優(yōu)先級(jí)只會(huì)影響調(diào)度,不會(huì)中斷更新的執(zhí)行。

老版React的歷史包袱

那么采用ReactDOM.render創(chuàng)建的應(yīng)用執(zhí)行順序又是怎么一回事呢?

記不記得一道經(jīng)典(且毫無(wú)意義)的React面試題:React的更新是同步還是異步的?

下面兩種情況,a打印的結(jié)果是1么?

// 情況1
onClick() {
this.setState({a: 1});
console.log(a);
}
// 情況2
onClick() {
setTimeout(() => {
this.setState({a: 1});
console.log(a);
})
}

其中,情況2中a打印結(jié)果是1。

之所以會(huì)有這種情況,是React早期實(shí)現(xiàn)批處理時(shí)的瑕疵造成的,并不是什么有意為之的特性。

當(dāng)React使用Fiber架構(gòu)重構(gòu)后,完全可以規(guī)避這個(gè)瑕疵。但為了與老版本行為保持一致,刻意實(shí)現(xiàn)成這樣。

所以,在我們的示例中,這兩個(gè)更新不會(huì)受到「優(yōu)先級(jí)」的影響,但會(huì)受到「為了兼容老版本」造成的影響:

setTimeout(() => {
setA(9000);
BtnRef.current?.click();
}, 2000);

React的執(zhí)行流程如下:

  1. a觸發(fā)更新,因?yàn)槭窃趕etTimeout中觸發(fā)的,所以會(huì)同步執(zhí)行后續(xù)更新流程。
  2. a對(duì)應(yīng)更新渲染到頁(yè)面中。
  3. b觸發(fā)更新,因?yàn)槭窃趕etTimeout中觸發(fā)的,所以會(huì)同步執(zhí)行后續(xù)更新流程。
  4. b對(duì)應(yīng)更新渲染到頁(yè)面中。

總結(jié)

React作為一款維護(hù)了快10年的框架,在經(jīng)歷重大版本更新后要保持框架行為前后一致,實(shí)屬不易。

更新順序的變化對(duì)一般應(yīng)用影響不大。

但是,如果你的應(yīng)用依賴更新后「頁(yè)面中當(dāng)前的值」作出后續(xù)判斷,那么需要注意升級(jí)到v18后的這些細(xì)微變化。

參考資料

[1]完整示例地址:


本文名稱:悄悄告訴你:React18文檔里寫錯(cuò)的地方
鏈接地址:http://www.5511xx.com/article/coidhge.html