react virtualized and InfiniteLoader - reactjs

I have the following sandBox https://codesandbox.io/s/mqk1z565qp with a custom implementation of react-virtualized using Table and InfiniteLoader components inspired by official documentation and examples. https://github.com/bvaughn/reactvirtualized/blob/master/docs/InfiniteLoader.md
but I am driving nuts when adding InfiniteLoader.
I need help from the community what is wrong with the current implementation and to help me to move forward.
In the current stand point initial data is not properly rendered. Only some of them are rendered... The expectation is that the first 50 batch of users are displayed with any interaction from user end. Why it is not happening right now?
Secondly when user scrolls down in some point a request should be done to the server for requesting next batch of rows (50 more). Right now, when user scrolls the example behaves wrongly.
As I understand from the documentation for each row a request is send to the server with a given startIndex / stopIndex.
Regarding this In a later stage have 2 thoughts pending to implement.
Reduce the number of request to the server. ideally only when scrolling is close to reach the bottom ask for next batch.
Translate from startIndex / stopIndex to a page param. My real API endpoint is the param that expects and not startIndex / stopIndex!
But for now I am happy enough having a scrollable table and loading data on demand through InfiniteLoader
note: I have a data.js. It fakes a resultset of data split in 3 pages.

Related

How to query/ lazy load next batch if the current result did not fill up the page in React native

I am currently building a calendar schedule view feature, where I have Month title as Header and the days as the items. I am currently fetching calendar event of about 6 weeks. which if the data is not present or so, it would still cover up the page and I can use onScrollEnd to query more data via useQuery.
But, I am trying to optimize my calendar feature and querying 6 weeks worth of events would not be ideal and would take time to load. thus, I was trying to find a way, where, if I can query let's say 1 week worth of data, if that does not have enough data (like 1-2 events) to cover the screen (for user to invoke onScrollEnd), then query next batch and so on and at the end wrapping the container with memo in order to help boost the load speed and lazy load data as required. Any idea how would this be possible?
I have looked at various examples of lazy loading such as:
https://snack.expo.dev/#johnborges/044274
etc, but my problem is that in these code examples, they do not cover the possibility of first or second batch/ page to have less data and querying for next page automatically.
I also thought of using FlatList nested with SectionList, but ended with conclusion that it would not be possible and data would be rendered twice.
What I want to happen:
<Schedule> --> component
render → Coordinate which Month in the SectionList should paginate through the events
<SectionList>
onEndReached → create more months
<Month>
<FlatList>
render → <Event />
onEndReached → fetch more events
<FlatList>
</Month>
</SectionList>
<Schedule>
So there are two "onEndReached" triggers, one to create more months when the user scrolls down the entire page and a second to get more events, when the user scrolls down the current month.
The Month component should just load 1 weeks worth of events at a time and paginate as the user is scrolling.. I somehow need some way to figure out that if the current week does not have enough data to cover the screen then query more data, and so one as always show the full page... Any help/ ideas would be appreciated. Thanks :).
I would try to measure the y position of the last element. If the y position is not close enough to the bottom, fetch more items. Store the previous fetch in the state. Add to that state the new fetch.

What's the right way to reset / initialize InfiniteLoader

I'm trying to use InfiniteLoader from the react-virtualize library to show up a scrollable list that has a textSearch input field on top (used to filter list entries).
The code I use is very close to the InfiniteLoader Sample Code.
The list is working fine, but I'm not sure how to reset/initialize the InfiniteLoader when the searchText is changed and (completely) new data should be shown.
The flow is like this:
the list is opened for the first time and shows data from the redux store (works fine).
user changes textSearch and new data is fetched to the store
at this point, InfiniteLoader should be be initialized (I tried calling resetLoadMoreRowsCache on InfiniteLoader)
InfiniteLoader should call loadMoreRows like for the first time and rerender with the new data
I've seen that the INFINITELOADER DEMO has the same behaviour: by clicking 'Flush Cached Data' nothing happens until I start scolling the list.
So my question: what is the right way to reset/initialize?
For newer versions of InfiniteLoader
Since this question has been posted, InfiniteLoader has gained a parameter which auto-reloads the data. You can now use:
infiniteLoaderRef.resetLoadMoreRowsCache(true);
to automatically flush the cache and get new rows.
For older versions of InfiniteLoader
InfiniteLoader reacts to a range of rows being rendered. The resetLoadMoreRowsCache method just resets cached data. It doesn't automatically request a batch of rows be loaded.
Arguably it should. I don't know. It seemed easy enough for user code to auto-load the first batch of new data if the application state has changed in such a way as to require resetLoadMoreRowsCache to be called.
Anyway, tl;dr is that you should be able to do this:
infiniteLoaderRef.resetLoadMoreRowsCache(); // Reset the cache
loadMoreRows({ // Manually kick off the first batch
startIndex: 0,
stopIndex: 20 // Or whatever
});
Happy to review a PR to change the default behavior if you feel it could be improved.

How to cache a page using AngularJS RouteProvider?

I have a standard Master > Details page in AngularJS setup using RouteProvider.
The Master page has a variation of "infinite scrolling" where Data can be added AND removed at both ends. Say, the user is looking at Contacts list, and has scrolled to 312th entry of the Contact List, only Contacts numbered 200-400 are kept, and the entries 1-200 are removed from Scope. Of course, when the user scrolls DOWN beyond 360, the list is appended with 401-500. And if the scrolls UP above 240, the list is "pre-pended" with 100-199.
Now, the user can click on a particular Contact and go to the Details page. Upon pressing 'Back' (window.history.back) how do I make the Master page re-render with,
Exact list 200-400 as it was when the page was left
Scrolled exactly to the position 312
(IMPORTANT) Listeners still listening correctly for scroll events beyond 360 or above 240?
Is this even possible? And if yes, please help me with how.
I'm not going to write code for this, it's a bit difficult without a deeper understanding of how your infinite scroll works but will offer some ideas
The first thing you would need would be to store the view state in a service and for more robust persistence ( page reloads or return visits) in localStorage synchronized with the service.
The main start point for the view state would be a start index so you know what to filter in your data array ... and either a length value that may or may not be constant in your app or an end index.
As for the scrolling you could use a scroll event handler in a directive to update the service object with offset scrollTop value in order to set on subsequent visit.... angular.element(containerElement)[0].scrollTop = service.scrollTop as a loose example
There is also $anchorScroll service that you could use by setting ID on each item
This won't give you a full solution but hopefully can get you started
Note that you will need to account for time it takes to render ng-repeat by defering to next digest cycle before trying to set scrollTop if you use that

React router - different content if post in list vs own page

React router has very cool feature: if you have a list of items (Instagram for example) and if you click on one item, content opens in modal/overlay but if you copy-paste the link to new tab/window or share the link with a friend for example, it opens in its own page.
I would love to use this feature but I need to find a custom solution..
My posts are very data heavy
I've split posts data into 2 tables in database
1st is very lightweight containing essential data: 4-5 columns
2nd table is very heave, ~30 columns
When user uses search filter, list updates only with data from 1st table
If user clicks on post, it will open in a modal/overlay
I will recycle the data I already have (from 1st table) and also get rest of the data from 2nd table
However, when user shares the link or opens it in new tab/page, data from 1st table is not present. I would need to integrate a conditional logic:
If post opens in list view (modal/overlay), only get additinal 2nd table data
If it's opened in a new tab/window in its own page, get all the data, 1st table included
How could I integrate this with React router? Has anyone already tried it? This would also allow to use different layout/components when user opens item in page view. Is there a way to check it?
Or is there a flaw in my logic? I imagine list would update very fast because it doesn't require huge amount of data and also would modal/overlay because it recycles some of the data.
I read all the docs, also searched online - didn't find anything.
Modals in react router are great. I've used the pinterest example and adapted it to my own needs.
Ensure you do your check on state.modal===true in a master layout component to give you the modal styling.
you'll need to check if table 1 stuff is present in your state and dispatch an action to trigger the async call in componentDidMount. You should be fetching table 2 in all scenarios.

Using google search api cursor in angular js app to get all results for google patent search

I want to make a search into google patent using the following URL which is obsolete
https://ajax.googleapis.com/ajax/services/search/patent?v=1.0&q=thumb%20wrestling%20apparatus&userip=192.168.1.102
It gives me limited number of records per page.
But at the end of the JSON it also returns the cursor which has start and label keys. So my question is that how can I use that cursor to show all the records in my search. Like if there are 8 pages and each page contains 4 records so I want to show all 32 records on my UI.
How can I achieve that?
And second question that is there REST APi for google patent search? If yes then how can I search the patent using REST API and how can I get all the records on one page?
It looks like the API is restricted to a maximum of 8 results per request (you can increase your current 4 results to 8 by using the query param rsz=8.
So I guess the only way to get all results is by performing multiple requests. So if the current page info data is...
"pages":[
{"start":"0","label":1},
{"start":"8","label":2},
{"start":"16","label":3},
{"start":"24","label":4},
{"start":"32","label":5}
]
You would make 5 requests chaining the start param start=0, start=8 ... and so on, extracting the results and pushing to an array store. If you're not already I recommend using something like Restangular, as it would make this process much easier.
Depending on how your UI is set out, it would be nice maybe to do this with some lazy loading as the user is scrolling through the list?

Resources