在 React.js 中加载异步数据时防止 UI 闪烁

Posted

技术标签:

【中文标题】在 React.js 中加载异步数据时防止 UI 闪烁【英文标题】:Preventing UI flicker when loading async data in React.js 【发布时间】:2015-09-10 00:57:51 【问题描述】:

我在IndexedDB中有一些数据,只能异步访问。我想使用该数据构建一个 React.js UI。总体思路是,我将拥有多个 React 组件,它们从 IndexedDB 加载数据并根据该数据显示一些 UI,用户将能够在当前显示的组件之间切换。

我担心的是,如果没有一些多余的 UI 闪烁,我不知道如何优雅地完成此任务。我可以在componentDidMount 中进行异步数据加载并将数据放入this.state,但随后将在完成之前调用render,这迫使我要么不显示任何内容,要么在一小部分时间内显示一些占位符数据同时检索 IndexedDB 中的数据。

我宁愿在我从 IndexedDB 中加载数据之前不要使用render。我知道加载不会花费很长时间,并且我希望在新数据加载时继续显示前一个组件,因此只有一个闪烁(旧 -> 新)而不是两个(旧 -> 空白/占位符-> 新的)。这更像是普通网页的工作方式。当您单击从一个网站到另一个网站的链接时,您的浏览器在等待链接网站的服务器响应时不会立即显示空白/占位符屏幕。

我想我可以在调用 React.render 之前在 React 组件之外加载数据,然后通过 this.props 传递它。但这看起来很混乱,因为嵌套组件会变得很棘手,而且我的一些组件会随着时间的推移而更新,并通过初始化它们的完全相同的代码从 IndexedDB 中提取新数据。因此,这似乎是在this.state 中存储数据的理想用例,因为当我收到新数据可用的信号时,我可以在组件本身内更新它。初始化和更新就像调用一个在this.state 中设置一些值的this.loadData() 函数一样简单...但是我有前面提到的额外闪烁。

有没有人有更好的想法?这个问题的规范解决方案是什么?真的只有毫秒级的空白/占位符闪烁吗?

【问题讨论】:

你试过了吗?在实践中,我对此并没有太多问题。 React 有一些底层的东西可以使事情保持同步。如果你真的需要,有一个加载视图并隐藏其他视图。然后在数据到达后关闭加载并显示其他视图。 哦,你可以考虑看看 Flux。如果您使用其中一种 Flux 实现,您将拥有一个包含数据的存储,并且视图将监听并重新呈现存储更改。效果很好。 那么在你有第一笔数据之前不要渲染任何东西。这看起来很简单。 我试过了。在渲染来自 IndexedDB 的异步数据之前,会有几分之一秒的可见闪烁。这让像我这样的人很困扰:)。我看不出通量会有什么影响。 Flux 不会神奇地将异步变为同步。如果我在加载数据之前不渲染任何东西,那么我的代码就会变得丑陋,如上一段所述。也许这是要走的路,但我是 React 新手,感觉不是“正确的方式”。 这取决于您要渲染的内容。例如,使用表格数据,您可以渲染空表并预设行高和行宽。你注意到 Facebook 是做什么的吗?它们显示带有占位符的通用提要,然后呈现到这些提要中。它并不完美,因为占位符与提要项目的大小不匹配,但它阻止了“从 0 到 300 像素”的事情。也许你可以有某种占位符? 【参考方案1】:

从 cmets 看来,您在之前的实现中的行为(等待导航直到您获取必要的数据)是期望的目标。如果是这种情况,在没有闪烁的情况下执行此操作的最佳方法是使用一些外部对象来管理状态并在获取数据时将数据作为道具传递。

React Router 有一个很好的解决方案,它有 willTransitionTo 钩子在导航之前为给定组件获取数据。这还有一个额外的好处,就是让您可以在出现问题时轻松捕获错误。

更新了新链接:

https://github.com/reactjs/react-router

【讨论】:

react-router 的新位置好像在这里:github.com/reactjs/react-router 我刚刚插入了 React Router - 这是一个很棒的解决方案。他们在他们的网站 (reacttraining.com/react-router) 上的培训视频是我用过的最有用的视频之一。

以上是关于在 React.js 中加载异步数据时防止 UI 闪烁的主要内容,如果未能解决你的问题,请参考以下文章

在tableview中加载异步图像,它们在每次滚动时消失

单击超链接时能够防止/停止在赛普拉斯中加载“页面加载”

加载 WebView 可防止在布局中加载其他视图

如何在每个 Worker 中的 Spark Dataframe 中加载数据,以防止将大量数据加载到 Master 节点

在 Vue 3 中加载异步选项时自动选择第一个 <select> 选项

使用 locationProvider 时,刷新浏览器网页不会在 ui-router 中加载