共计 1640 个字符,预计需要花费 5 分钟才能阅读完成。
大家好,我卡颂。
一些同学喜爱在 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
中,很多前端框架都有这样的问题。