I have some data in IndexedDB, which can only be accessed asynchronously. I want to build a React.js UI using that data. The general idea is that I'll have multiple React ponents that load data from IndexedDB and display some UI based on that data, and the user will be able to switch between which ponent is currently displayed.
My concern is that I don't know how to elegantly acplish this without some superfluous UI flickering. I can do my asynchronous data loading in ponentDidMount
and put the data in this.state
, but then render
will be called before it's finished, forcing me to either display nothing or display some placeholder data for a tiny fraction of a second while the data from IndexedDB is retrieved.
I'd rather have it not render
until after my data from IndexedDB is loaded. I know it won't take long to load, and I'd rather the previous ponent continue to display while the new data loads, so there is just one flicker (old -> new) rather than two (old -> blank/placeholder -> new). This is more like how a normal web page works. When you click a link from one website to another, your browser doesn't instantly show a blank/placeholder screen while it waits for the server from the linked website to respond.
I'm thinking I could do my data loading outside of the React ponent before calling React.render
and then passing it in via this.props
. But that seems messy, because nesting ponents would bee tricky and some of my ponents will be updating over time and pulling new data from IndexedDB, through the exact same code that initializes them. So it seems like an ideal use case for storing data in this.state
because then I could update it within the ponent itself when I get a signal that new data is available. Initialization and updating would be as easy as calling a this.loadData()
function that sets some values in this.state
... but then I have the aforementioned extra flicker.
Does anyone have any better ideas? What's the canonical solution to this problem? Is it really to just have millisecond blank/placeholder flickers all over the place?
I have some data in IndexedDB, which can only be accessed asynchronously. I want to build a React.js UI using that data. The general idea is that I'll have multiple React ponents that load data from IndexedDB and display some UI based on that data, and the user will be able to switch between which ponent is currently displayed.
My concern is that I don't know how to elegantly acplish this without some superfluous UI flickering. I can do my asynchronous data loading in ponentDidMount
and put the data in this.state
, but then render
will be called before it's finished, forcing me to either display nothing or display some placeholder data for a tiny fraction of a second while the data from IndexedDB is retrieved.
I'd rather have it not render
until after my data from IndexedDB is loaded. I know it won't take long to load, and I'd rather the previous ponent continue to display while the new data loads, so there is just one flicker (old -> new) rather than two (old -> blank/placeholder -> new). This is more like how a normal web page works. When you click a link from one website to another, your browser doesn't instantly show a blank/placeholder screen while it waits for the server from the linked website to respond.
I'm thinking I could do my data loading outside of the React ponent before calling React.render
and then passing it in via this.props
. But that seems messy, because nesting ponents would bee tricky and some of my ponents will be updating over time and pulling new data from IndexedDB, through the exact same code that initializes them. So it seems like an ideal use case for storing data in this.state
because then I could update it within the ponent itself when I get a signal that new data is available. Initialization and updating would be as easy as calling a this.loadData()
function that sets some values in this.state
... but then I have the aforementioned extra flicker.
Does anyone have any better ideas? What's the canonical solution to this problem? Is it really to just have millisecond blank/placeholder flickers all over the place?
Share Improve this question edited Jun 24, 2015 at 16:33 dumbmatter asked Jun 24, 2015 at 1:29 dumbmatterdumbmatter 9,6737 gold badges43 silver badges85 bronze badges 8- Have you tried it? In practice, I haven't had many problems with this. React has some bits under the hood that tend to keep things in sync. If you really need to, have a loading view and hide the other views. Then toggle off loading and show the other views after the data has arrived. – Cymen Commented Jun 24, 2015 at 1:36
- Oh, and you might consider looking at Flux. If you use one of the Flux implementations, you'd have a store that would have the data and the view would listen to and rerender on store change. Works out well. – Cymen Commented Jun 24, 2015 at 1:37
- Then don't render anything until you have the first bit of data. That seems straight forward. – Cymen Commented Jun 24, 2015 at 1:38
- I've tried it. There is a visible flicker for a fraction of a second before the async data from IndexedDB gets rendered. That bothers someone like me quite a bit :). I don't see how flux would make a difference. Flux doesn't magically turn async to sync. And if I don't render anything until data is loaded, then my code bees ugly as described in my last paragraph. Maybe that is the way to go, but I'm new to React and it just doesn't feel like the "right way". – dumbmatter Commented Jun 24, 2015 at 1:40
- It depends what you are rendering. For example, with tabular data, you can render the empty table and preset the row height and width. Have you noticed what Facebook does? They show a generic feed with placeholders and then render into those. It isn't perfect as the placeholders don't match the size of the feed items but it stops the "from 0 to 300px" kind of thing. Maybe you could have some sort of placeholder? – Cymen Commented Jun 24, 2015 at 2:16
1 Answer
Reset to default 7From the ments it sounds like the behavior you have in the previous implementation (waiting to navigate until you have fetched the necessary data) is the desired goal. If that's the case, the best way to do this without having the flickering would be to use some external object to manage the state and pass the data as props when it has been fetched.
React Router has a pretty good solution where it has the willTransitionTo hook to fetch data for a given ponent before navigating. This has the added benefit of allowing you to easily catch errors if something goes wrong.
Updated with new link:
https://github./reactjs/react-router