I have a list of about 200 items that I want to render. Since its only 200 items (about 200 rows in a table, each consisting of a short text phrase), I thought it'd be speedy to do it client side. I use a backbone collection and bind a react table component to it. BUT somehow it takes at least a few seconds before the entire table loads.
You can try for yourself by running https://github.com/tastejs/todomvc/tree/gh-pages/examples/react-backbone (when you fill the table with 200 items, and then refresh the page, these 200 rows take a few seconds to render initially). I realized the render method of the ENTIRE table is getting called 200 items, and since each render of the table means that the row gets re-rendered too, we get an insane number of render calls. Why is it that for each additional row, the entire render method of the table gets called even though I pull those rows at the same time in backbone via collection.fetch()? How do I speed things up if I don't want to render server-side?
After more investigation, I realized as backbone fetches a collection, it populates a model at a time. Each time a model is populated, render is called, and this slows down the process. I solved it by only rendering the component when the entire collection has been successfully fetched.
Related
I have a react-redux application which:
Loads N records from the database depending on a "limit" query parameter (by default 20 records) on first application load (initialization)
Every 10 seconds app requests same (or newer) records from the database to update data in real time
If a user changes filters - app requests new records from the database according to the filter and re-renders app (+ changes interval to load data according to the filters)
If users scrolls down, the app automatically loads more records.
The problem is that if a user for and instance tries to filter something out and at this same time interval is loading more data, 2 requests can clash and overwrite each other. How in react-redux app I can be sure in a request sequence. Maybe there is a common approach on how to properly queue requests?
Thanks in advance!
I am not sure what you mean by 'clash'. My understanding is that the following will happen:
Assuming that both requests are successful, then data is retrieved for each of them, the redux state will be updated twice, and the component which renders the updated state will render twice (and the time passed between the two renders might be very short, which might not be very pleasant to the user)
If you want only one of these two requests to refresh the component, then a possible solution may be the following:
Each request starts, before retrieval of data from the database, by creating a 'RETRIEVAL_START' action. 'RETRIEVAL_START' will set a redux state variable 'retrievalInProgress'
If you want, in such a case, to get results only from the 1st of the two requests, you can check, before calling the action creator from the component, if 'retrievalInProgress' is on. If it is, don't call the action creator (in other words, do not request data when a request is in progress). 'retrievalInProgress' will be cleared upon successful or failed retrieval of data.
If you want to get results only from the 2nd of the two requests, then make 'retrievalInProgress' a counter, instead of a boolean. In the 'retrievalSuccess' action of the reducer, if this counter is higher than 1, it means that a new request already started. In this case, do not update the state, but decrement the counter.
I hope that this makes sense. I cannot be 100% sure that this works before I test it, which I am not going to do :), but this is the approach I would take.
I have a requirement to consume huge volume of data ( like more than 100000 rows) by calling API end point and Data format is JSON and display them in react page. I am developing the logic using React-Table, but would like to hear experts opinion to know whether this is possible in reactjs? Is React-Table the right option in reactjs? Will there be performance issues?
Yes this is surely possible but involves the usage of virtual views like react-virtualized
The problem with 100k rows is that first render takes a lot of time, scroll could be tedious and every re-render takes a significant amount of time too.
With virtual views data is rendered only in active viewport and element are added/removed upon scroll reducing the rendering/reconciliation payload.
I'm trying to figure out the idiomatic way to address this:
I have a reducer that contains a list of “applied filters” and a list of “records”. When I change the filters or records, a list of “filtered records” should also change, but applying the filters to what can be a long list of records can be slow-ish.
Right now, I’m dispatching an “Add filter” or “Remove filter” action to change that list of “applied filters”. This results in recalculating the list of “filtered records” (currently done in the reducer).
I'm using two container components, one to display a list of "filter chips", the other to display the list of "filtered records".
Because applying the filters takes a while, and is done every time the filters change, the process of removing a filter from the UI seems laggy -- I click to remove a filter, and the removed filter doesn't disappear until the reducer finishes all its work, which includes updating the list of filters AND applying the new list of filters.
What I'd rather have is:
Remove the filter, and it disappears from the UI as quickly as possible. (i.e., a state change is broadcast that just includes the removed filter)
Concurrently, I'd like the process of applying the filters to occur in the background, and once that is finished, dispatch another action to change the list of filtered records.
After the filters have been applied and the action to update the filtered records has fired, I want my "filtered records list" component to update.
So, essentially I want a state change to potentially trigger ANOTHER state change, but I want to broadcast the intermediate state in between those two state changes.
I know I have to get the bulky logic out of my reducers and into an action, but I'm struggling with how/where that logic should be applied. I have that nagging feeling that I've wrapped my brain around its axle and I'm now overcomplicating things, but I can't seem to get back to the simple/correct method.
Any help would be greatly appreciated!
Edit, from a comment I added, but wanted to keep it inline here as well:
I mis-spoke in my original question, pretty big correction here --
I'm not actually calculating the "filtered record list" in the reducer -- I have a reselect selector on my "RecordList" container that takes in "records" and "filters" and returns a list of the filtered records.
I'm thinking this is more because of the "RecordList" render holding up the "FilterList" render, so I'm going to go up the component hierarchy and see if I can fix something there.
I'd still be up for any suggestions, though!
I'm pretty new to React / Redux, but love to play with it so far.
I came accros something that actually bothers me, but I'm not even sure it's a "real" issue I should care about. Anyway, here it is.
Let's say I have a component, which is actually a form for updating a record, retrieved from a database. This record has several foreign key to different tables. (Let's say my main table is Training, which has a Format, a Type, a Place... and all those data come from another tables).
In order to be able to display all the possible values for each of the foreign key to the user, I have to request all the different tables to get the data, and display those in dropdowns.
For now, I'm doing something like :
dispatch(new CrudActions(places).getAll());
dispatch(new CrudActions(trainingFormats).getAll());
dispatch(new CrudActions(trainingTypes).getAll());
Each of these line will dispatch a redux action, and so, update a part of the state, according to the data that is retrieved.
Then my component will then simply get the values from state :
function mapStateToProps(state) {
return {
places: state.places.list,
trainingFormats: state.trainingFormats.list,
trainingTypes: state.trainingTypes.list
}
}
It's actually working, but the consequence is : each time an action finishes and updates the state, my component get re-rendered... Let's imagine my main training has 10 foreign keys : for a single page load to display the update form, my component will be rendered 10 times.
Wouldn't it cause bad performances ? Is there any better way to retrieve foreign data ?
Let me rephrase that. Each of your record components has dropdowns for places, training format and training type. The dropdown options are retrieved via ajax. When you have several records, there will be a lot of requests and rerenderings.
The solution: Don't let every record component retrieve the dropdown values on its own. For each respective dropdown, they are all the same anyway. Instead load them in one of the parent components and pass them to the record components as properties, for example as availablePlaces, availableFormats, availableTypes.
Your parent component does not even have to load the available dropdown options via ajax. It can be initialized with it.
For further optimizations concerning rerendering have a look at https://facebook.github.io/react/docs/react-component.html#shouldcomponentupdate.
Facebook recommends making ajax calls in https://facebook.github.io/react/docs/react-component.html#componentdidupdate.
So yes, apparently it is possible to have long grid with lots of rows built with angular. But then a problem comes with data updates.
You see if I just get all (let's say 10 000 rows) and render them in my grid - that works. It just takes a few seconds initially. And
a) I don't have all the date up front
b) I need the grid to be responsive immediately.
I can just do that with throwing let's say only 100 rows at the beginning, and then slowly update data as it becomes available. And that turns out to be the problem. Everytime you push new rows into $scope.data - it blocks UI. So I need to be smart about these updates.
Maybe I should set an interval and update the data only every few seconds? That seems to be not working
Maybe I should somehow watch for mouse movements and once it stops moving - start/resume adding rows, once mouse-movement detected seize adding rows and wait for another chance? - What if user never stops moving the mouse? (say some sort of a psycho)
Experimenting with _.throtle and _.debounce didn't get me anywhere.
You guys have any ideas?
UPD: here's a crazy one: what if? instead of waiting till angular updates the DOM, create entire DOM structure in memory, right before the digest cycle (with no data) and then insert that HTML chunk (that would be faster, right?) And after that let angular do its magic, data should appear. Would that work?
You are going to run into performance issues when something changes even if you can get all those rows rendered to the DOM. And your user probably isn't going to scroll through 10000 rows anyway. I would just use pagination. e.g.:
<div ng-repeat="item in items | startFrom:currentPage*itemsPerPage | limitTo:itemsPerPage"></div>
If you really want to have everything on one page you could load the rows as the user scrolls. If you are interested in that solution checkout http://binarymuse.github.io/ngInfiniteScroll/
One of the things I've noticed that I stupidly used to ignore - the container has to have fixed height. That significantly makes updates faster. Although technically it doesn't solve the problem entirely