網(wǎng)站首頁(yè) 編程語(yǔ)言 正文
引言
一些同學(xué)喜歡在useEffect
中請(qǐng)求初始數(shù)據(jù),類似這樣:
useEffect(() => { fetch(xxx).then(data => setState(data.json())) }, [])
但React18
并不推薦這種方式。
這么寫有什么問(wèn)題?如果不推薦這種方式,那么推薦的方式是什么呢?
本文來(lái)看看Dan
在reddit是如何回答上述問(wèn)題的。
這是一個(gè)普遍的問(wèn)題
除了React
外,大部分以組件形式組織的前端框架,都有如下類似的API
:
effect
didMount
/didUpdate
如果有初始化時(shí)請(qǐng)求數(shù)據(jù)的需求,這類框架都會(huì)選擇在上述回調(diào)函數(shù)內(nèi)執(zhí)行請(qǐng)求操作,并在數(shù)據(jù)返回后更新狀態(tài)。
所以,這并不是React
獨(dú)有的問(wèn)題。相反,他很普遍。
之所以在React
中這么突出,是因?yàn)?code>React官方在引導(dǎo)開發(fā)者不要用這種形式書寫代碼(通過(guò)嚴(yán)格模式下useEffect執(zhí)行兩次放大這個(gè)問(wèn)題)。
而React
之所以這么做,是為了項(xiàng)目的性能以及UX(User Experience,用戶體驗(yàn))。
下面我們來(lái)細(xì)聊這么做的影響。注意,這些影響同樣適用于其他框架。
為什么不推薦這么寫?
需要解決競(jìng)態(tài)問(wèn)題
在useEffect
中請(qǐng)求數(shù)據(jù)要面臨的第一個(gè)問(wèn)題是需要解決競(jìng)態(tài)問(wèn)題。
假設(shè)你有個(gè)組件User
,接收userID
作為props
,用userID
請(qǐng)求數(shù)據(jù)后展示用戶信息。
下面是你的寫法:
function User({userID}) { const [data, setData] = useState(null); useEffect(() => { const res = await fetch(`https://xxx/${userID}/`); setData(res.json()); }, [userID]); if (data) { return <div>{data.name}</div>; } return null; }
這里有個(gè)開發(fā)階段很難復(fù)現(xiàn)的bug
—— 如果userID
變化足夠快,會(huì)發(fā)起多個(gè)不同的用戶請(qǐng)求。
而最終展示哪個(gè)用戶的數(shù)據(jù),取決于哪個(gè)請(qǐng)求先返回。這就是請(qǐng)求的競(jìng)態(tài)問(wèn)題。
點(diǎn)擊返回按鈕后重新請(qǐng)求數(shù)據(jù)
如果用戶跳轉(zhuǎn)到新的頁(yè)面后,又通過(guò)瀏覽器回退按鈕回到當(dāng)前頁(yè)面,并不能立刻看到他跳轉(zhuǎn)前的頁(yè)面。
相反,看到的可能是個(gè)白屏 —— 因?yàn)檫€需要重新執(zhí)行useEffect
獲取初始數(shù)據(jù)。
這個(gè)問(wèn)題的本質(zhì)原因是:沒(méi)有初始數(shù)據(jù)的緩存。
CSR時(shí)的白屏?xí)r間
CSR
(Client-Side Rendering,客戶端渲染)時(shí)在useEffect
中請(qǐng)求數(shù)據(jù),在數(shù)據(jù)返回前頁(yè)面都是白屏狀態(tài)。
瀑布問(wèn)題
如果父子組件都依賴useEffect
獲取初始數(shù)據(jù)渲染,那么整個(gè)渲染流程如下:
- 父組件
mount
- 父組件
useEffect
執(zhí)行,請(qǐng)求數(shù)據(jù) - 數(shù)據(jù)返回后重新渲染父組件
- 子組件
mount
- 子組件
useEffect
執(zhí)行,請(qǐng)求數(shù)據(jù) - 數(shù)據(jù)返回后重新渲染子組件
可見,當(dāng)父組件數(shù)據(jù)請(qǐng)求成功后子組件甚至還沒(méi)開始首屏渲染。
這就是渲染中的瀑布問(wèn)題 —— 數(shù)據(jù)像瀑布一樣一級(jí)一級(jí)向下流動(dòng),流到的組件才開始渲染,很低效。
既然直接寫useEffect
有這么多問(wèn)題,那么推薦的方式是什么呢?
推薦的方式
在Meta
公司內(nèi)部,基于Relay
驅(qū)動(dòng)數(shù)據(jù)(但請(qǐng)求數(shù)據(jù)要求使用GraphQL
),所以這套架構(gòu)比較難在社區(qū)普及開。
但是,現(xiàn)在社區(qū)已經(jīng)有了成熟的請(qǐng)求數(shù)據(jù)的方案。
對(duì)于SSR
,可以使用Next.js
、Remix
接管數(shù)據(jù)請(qǐng)求。
對(duì)于CSR
,可以使用React Query
、useSWR
接管數(shù)據(jù)請(qǐng)求。
這些成熟的方案都致力于解決上述提到的問(wèn)題。
如果不想使用這些方案,想自己寫,可以參考React
新文檔中下面兩篇文章:
使用effect同步數(shù)據(jù)
你可能不需要使用effect
想看中文的同學(xué),可以看我寫的總結(jié) —— React新文檔:不要濫用effect哦
總結(jié)
本文我們聊了React18
之后不推薦的請(qǐng)求數(shù)據(jù)的方式以及推薦的請(qǐng)求數(shù)據(jù)的方式。
其中不推薦的請(qǐng)求數(shù)據(jù)的方式不僅存在于React
中,很多前端框架都有這樣的問(wèn)題。
原文鏈接:https://juejin.cn/post/7115595794425577502
相關(guān)推薦
- 2022-10-22 React拖拽調(diào)整大小的組件_React
- 2022-09-24 Python?Matplotlib通過(guò)plt.subplots創(chuàng)建子繪圖_python
- 2022-06-29 docker容器狀態(tài)轉(zhuǎn)換管理命令實(shí)例詳解_docker
- 2023-01-19 Retrofit?創(chuàng)建網(wǎng)絡(luò)請(qǐng)求接口實(shí)例過(guò)程_Android
- 2023-02-18 SQLserver中的any和all運(yùn)算符的用法_MsSql
- 2022-12-04 pyecharts?X軸標(biāo)簽太長(zhǎng)被截?cái)嗟膯?wèn)題及解決_python
- 2024-03-09 基于 Redis 的 JWT令牌失效方案
- 2022-11-17 Android使用元數(shù)據(jù)實(shí)現(xiàn)配置信息的傳遞方法詳細(xì)介紹_Android
- 最近更新
-
- 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)證過(guò)濾器
- 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)-簡(jiǎn)單動(dòng)態(tài)字符串(SD
- arthas操作spring被代理目標(biāo)對(duì)象命令
- Spring中的單例模式應(yīng)用詳解
- 聊聊消息隊(duì)列,發(fā)送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠(yuǎn)程分支