I've created a SPA Hearthstone card search that shows all (currently ~1200) cards on the same page. Site. The problem I have is that due to all 1200 cards being displayed on the same page it takes really long time to render. How would I best tackle this problem?
My ideas so far:
Lazy render parts of array that aren't immediately visible. This would seem best, but I don't know if it's possible and how. There's a package for react that seems to do this, so I guess it's possible somehow? I guess I could make a separate array for shown cards, which I would lazy append from first array based on how much the user has scrolled
Pagination. Obvious one, but it makes for some counter-intuitive behaviour along with the filters I have. I would like to avoid using pagination if possible.
For reference - here's the code for rendering the cards.
How would I go about making this render faster? Is lazy rendering possible and how is it best done?
Related
So i'm seeking for a couple of questions to be answered. I am using a api which returns a list of products (15000+) how ever they use pagination so it only returns 20 per page.
I would like to be able to show all of this data on my shop so users can search through it etc... however, issue... it takes A LONG time to loop through it etc etc.
Is there a good method to do this? Shall I just loop through all the data and allow it to be added into an array once loaded? Is there something "special" we can do with the pagination?
I am new to this, and just seeking advice on the above.
Kind Regards,
Josh
There are a few thoughts that strike me straight away so let's cover those first:
From a pure UX perspective, it's very VERY unlikely that any user will ever need or click through 15k+ rows of whatever. So loading them all doesn't serve your user even if you could figure out how to do this in a efficient way.
Instead, look at what serves your users which likely in this case is some sort of filtering or search options. I would look into if your API has any support for things like categories (that should be a set smaller than 1 request maybe) which is much easier to display to get the user to cut down a lot of the data set. Then also look into if they offer some sort of query or search filter, maybe the names of whatever is being displayed. This further lets your users zoom down to a dataset that is manageable (roughly 100 items max). From there, 20 items per page is just 5 pages. Still though, you should only really load 1 page at a time and focus on better ways to offer SORTING, if you can find what the user needs on the first page, you don't need to load those 4 other pages. Hope that gives you some ideas of what to look for inside your API, or what to add if you can add it yourself.
If not, perhaps it would be worth considering loading the data into your own database and set up some background/nightly task that fetches any updates from the API and stores them. Then you build your own API around your own database that has functionality for filtering/searching.
A final option is indeed to simply ask for the first page, and then display that while you wait for the 2nd page to load. But this risks making an awful amount of wasted requests which wastes not only your users bandwidth but also puts pressure on the API for what is likely going to be wasted work. So there are a few other UX ideas around this as well, like infinite scrolling. Load the first 1 or 2 pages then stop, until the users scrolls past the first page and a half, then request page 3 etc. This way you only load pages as the user scrolls but it's a bit more fluid than pagination with numbering. Still, you'd likely want to offer some way to sort this set so that it becomes more likely that they'll find what they need in the first few "pages".
I have a component that wraps a bunch of ReactList components.
ReactList component is a component that does infinite scrolling ie only load what's on viewport. It has couple of modes: simple and uniform. I'm using simple which just loads and loads as you scroll down (making the scrollable page longer). Uniform loads and removes the above section that is now out of viewport. I tried using uniform mode, and if it worked I wouldn't even need to ask what I'm about to, but it's super buggy and defeats the purpose. Simple on the other hand is super fast scrolling and loading is equally fast.
I broken down my list into few groups where user can click and it will load that ReactList component. If the scrollable page is short, ie, user hasn't scrolled all the way down, changing between the group of lists is fast enough. ~2s. However, if the page is scrolled all the way down, and trying to change list takes ~6s.
I noticed that the page is fully loaded too, ie nothing more to load. So okay, I think maybe if I change the key for the wrapper parent component and just remount the component, it should be fast right? Nope. The component that reloads is short, only one viewport length, but it takes around ~5s.
I noticed changing out of the fully loaded list component page to just regular single line text "Hello world" component still took around the same amount! ~5s. What's up with that?
QUESTION: Why is unmounting a long page with many small components in a list take so long to just unmount?
Sorry I realize this is long and full of text but I thought I should explain my situation.
As it is an old question, I really want to put it to an end.
Quick answer: use virtual list, something like uniform mode you described, but better maintained with better api. You can get bunch of packages if you search react virtual list, use ones with more stars and better maintained, and most of all fit your case.
Surely you got lots of small components when you scroll. In react it's not like removing a node is one shot thing, it needs to unmount every leaf from the tree, and recursively unmount leaves untuil reach that node. So if you got a lot of components, even today's new react won't help you out.
With virtual list, you get less components although your user doesn't know, so it would be quick.
So I have an app that has a right sidebar whose visibility is toggled via a button. In that sidebar there can be one of several things [at a time] - chat, help, search. I was looking at some plain HTML from apps which have a similar feature and noticed that they have all nodes rendered, but are just hidden via CSS.
Since I need to do the same thing, I was thinking whether this would be a good idea to do with React. But then I realized that React elements have a state which when updated calls the render method. So I can use the state to store both whether the sidebar is opened, and what is inside the sidebar.
Is that the React way of doing things? Is it better to have all nodes rendered even if they are not visible, or is it better to have the nodes rendered on request via state changes?
My feeling is that only rendering what is visible would be the more standard React way, but in this case, this is mainly a performance decision. If you render everything and just toggle visibility with CSS, the first render will take longer (but the time difference may not be relevant or even noticeable). If you render only the part that's visible, React needs to do a small rerender every time the sidebar content changes. (This may also not be noticeable time.)
My recommendation would be to try both, if you want to test the performance. But I think you won't go too wrong either way.
I'm developping an angular app right now for my company, but I reached a point where the app became extremely slow so I tried tunning it by using onetimebind everywhere I can, track by ...but it's faster to load at first but still laggy, it is composed of a pretty much huge nested objects, I've counted the total number of objects, it starts at 680 and can go up to +6000 for normal use of the app, oh yeah I should precise that the app is generating a form and pretty much +90% of the objects in the scope belongs to an input and are updated each time the client click(radio) keyup/change(text).
It also have like 5/6 arrays composed of objects and the array gets bigger/smaller accodring to the clients choice, and that's where it gets laggy, each time I add an object to the array, it takes like a second to render it, so I tried using nested controllers thinking that if the child of an object is updated Angular will render only this child and not all the others, but somehow the app got even slower and laggier :s (it's a bit faster when I use ng-show instead of ng-if but the memory used jumps from ~50Mb to ~150Mb)
I should also precise that the form is in a wizard style, and not all the inputs are displayed at once, the number of inputs that are displayed are between 10%-20% of the total inputs
Has anyone encountred this problem before? does anyone know how to deal with big scopes?
Sad to say, but that's intrinsic of the view rendering in angular.
An update in the model triggers a potential redraw of the entire view. No matter if you have elements hidden or not. The two way data binding can really kill performances. You can consider evaluate if you need to render the view only once, in that case there are optimizations, but I'm assuming that your form change dynamically, therefore a 2 way data binding is necessary.
You can try to work around this limitation but encapsulate sub part of the entire MVC. In this way a contained controllers only update the specific view associated to that scope.
You may want to consider using react (that has as first goal to address exactly your use case)
Have a look at this blog post for a comparison of the rendering pipeline between angular and react Js.
http://www.williambrownstreet.net/blog/2014/04/faster-angularjs-rendering-angularjs-and-reactjs/
Recently I had to make an interface that necessitated many items with numerous checkbox fields to be displayed and interacted with (here is a link to a screengrab of a small portion of such a list http://i.imgur.com/hMtGSL4.png).
My issue was that AngularJS would get unreasonably slow pretty quickly. My question is What steps could one take to optimize ng-repeat and displaying items with many fields?
I have tried with varying degrees of improvement (based on what I could come up with and other stackoverflow posts):
Formatting the data before it gets to the view so as to not use any AngularJS filtering/sorting.
Simplifying the data as much as possible (checkbox fields being arrays of booleans, etc)
Splitting the data into groups that, when clicked, loaded the relevant items (hence the gray bars in the picture). This is more of a pragmatic solution though, rather than straight up AngularJS optimization.
Lazy loading scroll, scrolling to the bottom of the screen loads more items below the fold (also, more of a pragmatic solution).
Using directives to dynamically generate a form, and then use jquery for saving the data after manipulation. Without $watch on items anymore it certainly was more efficient, but largely defeated the benefits of using AngularJS.
Thank you, and hopefully this question and its answers can serve as a good resource for AngularJS specific techniques one can use in such a situation.