網站首頁 編程語言 正文
引言
一些同學喜歡在useEffect
中請求初始數據,類似這樣:
useEffect(() => { fetch(xxx).then(data => setState(data.json())) }, [])
但React18
并不推薦這種方式。
這么寫有什么問題?如果不推薦這種方式,那么推薦的方式是什么呢?
本文來看看Dan
在reddit是如何回答上述問題的。
這是一個普遍的問題
除了React
外,大部分以組件形式組織的前端框架,都有如下類似的API
:
effect
didMount
/didUpdate
如果有初始化時請求數據的需求,這類框架都會選擇在上述回調函數內執行請求操作,并在數據返回后更新狀態。
所以,這并不是React
獨有的問題。相反,他很普遍。
之所以在React
中這么突出,是因為React
官方在引導開發者不要用這種形式書寫代碼(通過嚴格模式下useEffect執行兩次放大這個問題)。
而React
之所以這么做,是為了項目的性能以及UX(User Experience,用戶體驗)。
下面我們來細聊這么做的影響。注意,這些影響同樣適用于其他框架。
為什么不推薦這么寫?
需要解決競態問題
在useEffect
中請求數據要面臨的第一個問題是需要解決競態問題。
假設你有個組件User
,接收userID
作為props
,用userID
請求數據后展示用戶信息。
下面是你的寫法:
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; }
這里有個開發階段很難復現的bug
—— 如果userID
變化足夠快,會發起多個不同的用戶請求。
而最終展示哪個用戶的數據,取決于哪個請求先返回。這就是請求的競態問題。
點擊返回按鈕后重新請求數據
如果用戶跳轉到新的頁面后,又通過瀏覽器回退按鈕回到當前頁面,并不能立刻看到他跳轉前的頁面。
相反,看到的可能是個白屏 —— 因為還需要重新執行useEffect
獲取初始數據。
這個問題的本質原因是:沒有初始數據的緩存。
CSR時的白屏時間
CSR
(Client-Side Rendering,客戶端渲染)時在useEffect
中請求數據,在數據返回前頁面都是白屏狀態。
瀑布問題
如果父子組件都依賴useEffect
獲取初始數據渲染,那么整個渲染流程如下:
- 父組件
mount
- 父組件
useEffect
執行,請求數據 - 數據返回后重新渲染父組件
- 子組件
mount
- 子組件
useEffect
執行,請求數據 - 數據返回后重新渲染子組件
可見,當父組件數據請求成功后子組件甚至還沒開始首屏渲染。
這就是渲染中的瀑布問題 —— 數據像瀑布一樣一級一級向下流動,流到的組件才開始渲染,很低效。
既然直接寫useEffect
有這么多問題,那么推薦的方式是什么呢?
推薦的方式
在Meta
公司內部,基于Relay
驅動數據(但請求數據要求使用GraphQL
),所以這套架構比較難在社區普及開。
但是,現在社區已經有了成熟的請求數據的方案。
對于SSR
,可以使用Next.js
、Remix
接管數據請求。
對于CSR
,可以使用React Query
、useSWR
接管數據請求。
這些成熟的方案都致力于解決上述提到的問題。
如果不想使用這些方案,想自己寫,可以參考React
新文檔中下面兩篇文章:
使用effect同步數據
你可能不需要使用effect
想看中文的同學,可以看我寫的總結 —— React新文檔:不要濫用effect哦
總結
本文我們聊了React18
之后不推薦的請求數據的方式以及推薦的請求數據的方式。
其中不推薦的請求數據的方式不僅存在于React
中,很多前端框架都有這樣的問題。
原文鏈接:https://juejin.cn/post/7115595794425577502
相關推薦
- 2022-08-06 Python導入不同文件夾中文件的方法詳解_python
- 2022-03-03 sublime-text - Sublime Text 3,在注釋的下一行,如何取消自動注釋?
- 2022-12-28 Python標準庫之urllib和urllib3的使用及說明_python
- 2022-09-22 Windows MongoDB服務無法啟動,錯誤 1053的一種情況和解決辦法
- 2022-03-29 帶你了解C++中vector的用法_C 語言
- 2023-08-01 頁面滾動時隱藏element-ui下拉框/時間彈框
- 2023-10-14 SQL Server 執行sql報錯'sys.sp_OACreate' 的訪問
- 2023-03-20 C#中程序自刪除實現方法_C#教程
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支