Preventing UI flicker when loading async data in React.js - javascript

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 components that load data from IndexedDB and display some UI based on that data, and the user will be able to switch between which component is currently displayed.
My concern is that I don't know how to elegantly accomplish this without some superfluous UI flickering. I can do my asynchronous data loading in componentDidMount 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 component 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 component before calling React.render and then passing it in via this.props. But that seems messy, because nesting components would become tricky and some of my components 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 component 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?

From the comments 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 component before navigating. This has the added benefit of allowing you to easily catch errors if something goes wrong.
Updated with new link:
https://github.com/reactjs/react-router

Related

Is there a way to preserve DOM state of the component after navigating away and back in Angular

After researching the issue for a few days I've seem to have reached a dead end.
I'm dealing with, what I assumed, was a fairly common scenario: After user navigates to a certain page and makes some changes (content of an input field, scroll through grid data or even changing some editable cell values ), he navigates to different page. When user returns to original page, all of the changes must remain the same.
Now, that means that cursor in the aforementioned input field must be in the same place, scroll position in the grid and changed cell values, as well as any other changes user made, must be preserved.
Solutions like storing data in localStorage, using services or even custom reuse strategy will not work, because saving that amount of information contained in multiple sub components will be impossible.
Currently, I'm considering DOM manipulation, where rendered template will be moved to a container in parent component in onDestroy hook, and returned later in onInit. That, of course, is a hail Mary attempt and feels very unnatural.
I'm hoping someone had (and solved) this problem before because, like I've mentioned, it seams like fairly common use pattern.
There is not much option to do this in angular compared to React,
What I can recommend you is, store all the data in "environment" as object and when user routes back populate data from environment.
Usually I do this, when a component loads I store values in objects. When on destroy called all this objects goes to the environment under a one main object.
When oninit calls I am checking if object has values and restoring the page to where it was.
I think you are looking for Angular RouteReuseStrategy, where Angular can cache some routes state, without destroying the component state, so when ever the user visit the same route a cached view will be used,
RouteReuseStrategy Docs.
You can also check this medium article, implementing the required methods
Medium
for small amount data we can use services or localstorage as you mentioned
for large amount data we can go with
NgRx
https://dzone.com/articles/angular-app-state-management-with-ngrx
I use a service for this purpose, saving and restoring the state of the page from an object stored in the service but i haven't been able to figure out how persist the result of a user file upload where i am holding a user uploaded image
Pending file upload to cloud storage. Any ideas on solving this helpful as it seems like the cached file is cleared by angular navigation process

React app - render a feed in the background

I was looking to build a feed into a react app that as you were scrolling through it it will constantly fetch more data to display to you (it basically has no end). I was looking for a way to avoid re-rendering the whole feed every time new data was fetched to be displayed to the user since it will start to get slow to re-render the whole component after a while.
I know I can do it with server-side rendering or through ReactDom.createPortal to render the element outside the react tree. The first option is out since that would be the only thing I would need a backend for and is not worth it.
The second option looks like the way to go but I am not sure if I can still access the state object and other react features from within the component rendered outside the react tree (I don't know if I would really need them or not but having them can't be bad)
Outside those two options, is there any other that I am not aware of?

Route wait for async data before redirect

I came from Angular world where resolve data for route is realy easy and out of the box. How can I do the same action in react?
Add async data loder for route so that redirect will after data is ready? I am using react-router.
I saw somewhere that I could use the Router.run() method to write own callback, but I can not find it in the official documentation.
I do not want to use componentWillMount because sometimes the data loads in seconds and the page flashes.
I know that the topic appears many times, but I can not find a satatory answer. I will be very graceful for help with the solution.
In my opinion, waiting for data before redirecting may cause bad user experience, because the user will need to wait something and he may not understand that the application is actually doing something in background.
It is better to render the UI and then take care of delivering the actual data to the page.
I usually use componentDidMount for such things.
E.g.:
Component is rendered without the data
Data is fetched within componentDidMount
The UI is then updated by setting the state
Depending on the specific look of the component, a loading icon can be shown as well.

How can I improve the performance of passing around a large JSON object in React Native?

I'm building an app with React Native and on my transitions, where I'm loading more data, it's very slow and I'm wondering if there's a better way to structure my app to avoid these shutdowns, which get longer as the JSON file gets larger.
Let's say I have
var data = require('./data/data.json')
in my index view, I think pass this data to a view, which then splits it up to other views like items={data[section_name]} and it goes down recursively like that further down the hierarchy. Creating smaller dicts on each level. And even with small objects it is still quite slow.
The JSON files I'm working with are from 3-8 MBs.
I understand what you want do to with your big data in your project, because I did the same way before for my react-native app.
Actually, this way is fine, it's kind of loading the data once only, then we can retrieve hierarchy easily like items={data[section_name]}
However, the problem now is it may take a while for processing the big data!
Therefore, the idea is we should move the part of loading/initializing the data asynchronously, move it somewhere out of our view, so that the view's transition as well as its other things will not be affected! Then, when the data are being loaded/processed, we may show something like fade-in, fade-out effects, on the view, so it will take a short-time (300-1000ms). However, in my opinion, there may be a better way for this: when the application is opened for the first time, when the splash screen is being shown (for a few seconds, this behavior is common, we can load the big data in the background here!)
FYI, my application loads big data using ajax, it will even take longer than loading local files, but using my above-mentioned way, nobody complains about the data-loading speed ^^ (actually, users don't know and don't see where and when data are loaded, when the app goes to its home/top page, everything has been fully loaded)
Now it comes to the important part of my answer: I suggest you using Flux/Redux for this, maybe Flux is easier for you now, because Redux is kind of an improvement based on Flux (in either Flux or Redux, we will have a Store, and this Store will work asynchronously, you can store your big JSON data here):
https://www.atlassian.com/blog/software-teams/flux-architecture-step-by-step
Flux can be applied on reactjs and react-native of course, you may find there are several new definitions if you don't know about Flux or Redux yet, however, it's really worth reading and trying! After you understand it, it'll be very easy and then you can apply that architecture on whatever react project you like ^^

How does one run code in a Vue component only once per page (when more than one of the same component exists on that page)?

So I have a Vue component which has two functions. One attaches some data and populates various tags with that data, another gets the data from a json file and parses through it - applying it to the other function.
(pseudo-code ahead!)
mounted: function() {
function listBuilder(data) { some code }
$.get("some-json"), function (data) {
[some code...]
listBuilder(data);
}
}
On the page itself, this component exists twice.
<section>
<my-component type="map"></my-component>
</section>
<aside>
<my-component></my-component>
</aside>
One component renders out the data in map form, while the other renders it out as a list. This all works just fine & dandy, except that on the map the data is rendered 2x - because, as you might have guessed, the component's logic is run twice - getting the json twice and processing it twice.
Is there a native "Vue" way to have (or designate) the code in the component to only run once on a page? I have a rather (in my opinion), hacky way of avoiding this right now, by applying a property to one of the components ("dumb"), that essentially skips some of the logic via a check if that property exists. I feel there has got to be a more elegant and native way to handle this, however, but have come up dry in my google searches.
One possible way is to have the component data loading moved to another parent element. Other way of doing this is to have one global store (like vuex) and then load the data out of it. This is just the type of problem vuex is solving. If you don't want to use vuex just use the browser's Window.sessionStorage it is well supported and you can store all the data you need in it. It is session based so you won't need to load the information every time.
Well I'm sure you'll get different responses, but I would have to agree with #pinoyyid and suggest extracting http part into a service for start, and then I would implement Vuex ( centralized local data that can be fairly easily integrated with Vue ) and then use Vuex actions and getters to get and process data. This will completely separate your vue component from fetching and data processing. You will only fetch your data once and then use it as many times as you'd like. And last but not least testing will be possible unlike now.

Categories