react18 來了,我 get 到...
點擊上方藍色字體,選擇“標星公眾號”
優(yōu)質文章,第一時間送達

-? ?1. automatic batching:自動批處理。? ? -
batching 批處理,說的是,可以將回調函數(shù)中多個 setState 事件合并為一次渲染,因此是異步的。
解決的問題是多次同值、不同值 setState, 期望最后顯示的是最后一次 setState 的結果,減少渲染。
??const?Index?=?()?=>?{
????const?[name,?setName]?=?useState('')
????const?[age,?setAge]?=?useState(0)
????
????const?change?=?()?=>?{
??????setName('a')
??????setAge(1)?
??????//?僅觸發(fā)一次渲染,批處理,2次setState合并為一次渲染
??????//?需需要立即重渲染,需要手動調用
??????//?ReactDOM.flushSync(()?=>?{
??????//???setName('a')?//?立即執(zhí)行渲染
??????//???setAge(1)?//?立即執(zhí)行渲染
??????//???//?不會合并處理,即沒有批處理,觸發(fā)2次
??????//?});
????}
????console.log(1)?//?只打印一次
????return?(
??????
????????name:?{name}
????????age:?{age}
????????
??????
????)
??}但是 react 18 之前,在 promise、timeout 或者 event 回調中調用多次 setState,由于丟失了上下文,無法做合并處理,所以每次 setState 調用都會立即觸發(fā)一次重渲染:
?const?Index?=?()?=>?{
???const?[name,?setName]?=?useState('')
???const?[age,?setAge]?=?useState(0)
???
???const?change?=?()?=>?{
?????setTimeout(()?=>?{
???????setName('a')?//?立即執(zhí)行渲染
???????setAge(1)?//?立即執(zhí)行渲染
???????//?不會合并處理,即沒有批處理,觸發(fā)2次
???????//?若需要批處理,需要手動調用
???????//?ReactDom.unstable_batchedUpdates(()?=>?{
???????//???setName('a')
???????//???setAge(1)?
???????//???//?合并處理
???????//?})
???????//?并且將?ReactDOM.render?替換為?ReactDOM.createRoot?調用方式
???????//?舊?ReactDOM.render("home"?/>,?container);
???????//?新?ReactDOM.createRoot(container).render("home"?/>)
?????},?0);
???}
???console.log(1)?//?打印2次
???return?(
?????
???????name:?{name}
???????age:?{age}
???????
?????
???)
?} react18,在 promise、timeout 或者 event 回調中調用多次 setState,會合并為一次渲染。提升渲染性能。
v18實現(xiàn)「自動批處理」的關鍵在于兩點:
增加調度的流程
不以全局變量 executionContext 為批處理依據(jù),而是以更新的「優(yōu)先級」為依據(jù)

-? ?2. concurrent apis:全新的并發(fā) api比如:startTransition? ? -
Concurrent:并發(fā),采用可中斷的遍歷方式更新 Fiber Reconciler。是漸進升級策略的產(chǎn)物。
不同更新觸發(fā)的視圖變化是有輕重緩急的,讓高優(yōu)更新對應的視圖變化先渲染,那么就能在設備性能不變的情況下,讓用戶更快看到他們想看到的UI。
案例:用戶操作滑塊,然后響應樹的變化?;瑝K響應是高優(yōu)先級的,而樹的變化可以認為是低優(yōu)先級的。
demo
未開啟:可以看到滑塊的拖動有卡頓

開啟:可以看到滑塊的拖動,非常的絲滑順暢

代碼實現(xiàn),將設置更新樹的 setState,放到 startTransition 中。而更新滑塊的不變,認為是高優(yōu)先級,優(yōu)先響應。
2部分:
緊急響應:滑塊。
過渡更新:根據(jù)滑塊,呈現(xiàn)結果內容。
?import?{?useTransition?}?from?'react';
??const?[isPending,?startTransition]?=?useTransition();
??//?更改滑塊觸發(fā)
??function?changeTreeLean(event)?{
??????const?value?=?Number(event.target.value);
??????setTreeLeanInput(value);?//?更新滑塊
??????//?是否開啟startTransition
??????if?(enableStartTransition)?{
????????startTransition(()?=>?{
????????? setTreeLean(value);?//?這個變慢,根據(jù)滑塊,呈現(xiàn)結果內容。
????????});
????????// react18之前,想要有類似功能。變體,setTimeout,防抖節(jié)流
????????//?setTimeout(()?=>?{
????????//???setTreeLean(value)
????????//?},?0)
??????}?else?{
????????setTreeLean(value);
??????}
??}
??//?過渡期間可以這么處理
??{isPending??? ?:?} 比 setTimeout 更好,能有狀態(tài) isPending,且更早更快的呈現(xiàn)更新到界面上(微任務里處理)。而且 setTimeout 是不可中斷的,而 startTransition 是可中斷的,不會影響頁面交互響應。
依賴于React底層實現(xiàn)的優(yōu)先級調度模型,被 startTransition 包含的 setState 的優(yōu)先級會被設置為低優(yōu)先級的過渡更新。

-? ?3. suspense:更好的 suspense。更好的支持在 ssr 和 異步數(shù)據(jù) 場景下使用 suspense。? ? -
1. ssr 下支持,可參考:React18 中的新 Suspense SSR 架構
2.透明的異步數(shù)據(jù)處理(未來18.x支持)
和寫同步邏輯代碼一樣,寫異步代碼邏輯。大大的簡化了代碼邏輯的書寫。把代數(shù)效應應用到極致了,把異步的副作用剝離了。
代數(shù)效應是函數(shù)式編程中的一個概念,用于將副作用從函數(shù)調用中分離。
場景案例:demo,顯示暢銷書排行榜。

其中,名稱和日期是一個接口獲取,而下面的列表是另一個接口獲取。
從圖中,可以明顯感到 with suspense 的效果更絲滑,用戶體驗更好。而代碼也非常簡潔。部分代碼如下:
//?接口部分
import?{?fetch?}?from?"react-fetch"
export?function?fetchBookLists()?{
??const?res?=?fetch(`
??https://api.nytimes.com/svc/books/v3/lists/names.json?api-key=${API_KEY}`)
??const?json?=?res.json()
??if?(json.status?===?"OK")?{
????return?json.results
??}?else?{
????console.log(json)
????throw?new?Error("Loading?failed,?likely?rate?limit")
??}
}
//?組件部分
//?沒有處理?loading?狀態(tài)等的異步處理,和同步已經(jīng)完全一致的代碼書寫
const?Content?=?()?=>?{
??const?list?=?fetchBookLists()[0]
??return?(
????<>
??????From?{list.display_name}
??????
????????Published?on?{list.newest_published_date}
??????
??????
????>
??)
}
export?const?BestSellers?=?()?=>?{
??return?(
???? }>
??????{/*?loading?must?happen?inside?a??*/}
??????
????
??)
}而在 react18 之前,你得這么寫:
//?接口部分
import?{?fetch?}?from?"react-fetch"
export?async?function?fetchBookLists()?{
??const?res?=?await?fetch(`
??https://api.nytimes.com/svc/books/v3/lists/names.json?api-key=${API_KEY}`)
??const?json?=?await?res.json()
??if?(json.status?===?"OK")?{
????return?json.results
??}?else?{
????console.log(json)
????throw?new?Error("Loading?failed,?likely?rate?limit")
??}
}
//?組件部分,按照異步的邏輯寫,寫loading,對異步結果的處理等
function?useNYTBestSellerLists()?{
??//?poor?man's?useQuery?implementation
??const?[isLoading,?setIsLoading]?=?useState(false)
??const?[lists,?setLists]?=?useState(null)
??useEffect(()?=>?{
????setIsLoading(true)
????fetchBookLists()
??????.then((lists)?=>?{
????????setLists(lists)
????????setIsLoading(false)
??????})
??????.catch(()?=>?setIsLoading(false))
??},?[])
??return?{?isLoading,?lists?}
}
export?const?BestSellers?=?()?=>?{
??const?{?isLoading,?lists?}?=?useNYTBestSellerLists();
??if?(isLoading)?{
????return? ;
??}
??if?(!lists)?{
????return?"not?loading?or?error";
??}
??const?list?=?lists[0];
??return?(
????<>
??????From?{list.display_name}
??????
????????Published?on?{list.newest_published_date}
??????
??????
????>
??);
}3.優(yōu)化 suspense 的行為表現(xiàn)。
場景舉例:
????loading...}>
?????? ?//?為?React.lazy?包裹的異步加載組件
?????? ?//?普通組件
???? 由于 Suspense 會等待子孫組件中的異步請求完畢后再渲染,所以當代碼運行時頁面首先會渲染 fallback:loading。而在loading這個過程中,頁面表現(xiàn)是一致的,但是背后的行為是不一致的:
react18 之前:即在 Legacy Suspense 中,Sibling 組件會立即安裝到 DOM 并觸發(fā)其效果/生命周期。頁面上隱藏。
react18:即在 Concurrent Suspense 中,Sibling 組件沒有掛載到 DOM。它的效果/生命周期也不會在 ComponentThatSuspends 解決之前觸發(fā)。

react18,Sibling 不會執(zhí)行,會等 suspense 包裹的組件都加載完才執(zhí)行渲染

優(yōu)化的是提交渲染的流程:
打斷兄弟組件并阻止他們提交。等待提交 Suspense 邊界內的所有內容- 掛起的組件及其所有兄弟組件 - 直到掛起的數(shù)據(jù)解決。然后在一個單一的、一致的批次中同時提交整個樹渲染。

-? ?4. 其他? ? -
比如:新 Hook —— useId
解決問題:ssr 場景下,客戶端、服務端生成的id不匹配!官方推出 Hook——useId解決,每個 id 代表該組件在組件樹中的層級結構。
function?Checkbox()?{
??//?生成唯一、穩(wěn)定id
??const?id?=?useId();
??return?(
????<>
??????
??????type="checkbox"?name="react"?id={id}?/>
????>
??);
);

-? ?最后? ? -
這幾個重大的更新,目的都是較少渲染、根據(jù)優(yōu)先級響應、提升性能、擁有更好的體驗。非常值得期待。
想嘗鮮的可安裝 react18 beta 版(2021-11-16發(fā)布的)
#?npm
npm?install?react@beta?react-dom@beta
#?yarn
yarn?add?react@beta?react-dom@beta
? 作者?|??ESnail
來源 |??cnblogs.com/EnSnail/p/15679835.html
