I'm new in ReactJs.
I need a lazy loader in my application when page is scroll down,
I'm using (https://jasonslyvia.github.io/react-lazyload/examples/#/normal?_k=rz3oyn)
Actually, this is working fine but first time it load all data.
I want to make api call and set data when page will scroll down.
Thank you.
Most probably what you need is an infinite scroll functionality. There are some good options for React when it comes to loading asynchronous data:
1) If you need high performance (a lot of results coming from the server) you can try react-infinite. As docs say:
React Infinite solves this by rendering only DOM nodes that the user
is able to see or might soon see.
2) Another simple option would be: react-infinite-scroller
General principle to make these libraries work is to pass their props which will let the module know when to make a request or when to wait.
<InfiniteScroll
pageStart={0}
loadMore={loadFunc}
hasMore={true || false}
loader={<div className="loader">Loading ...</div>}
>
{items} // <-- This is the content you want to load
</InfiniteScroll>
loadFunc will make an API call to the server and will set hasMore to false until it is successfully resolved.
Related
Approach I used:
I create a single Redux State ' API_IN_PROCESS ' which is set to TRUE if any API is called and to FALSE when it gives Response.
Based on its state, I show SPINNER/LOADER on the Pages.
Issue I'm facing is:
If I have two separate API calls on PAGE-1 and PAGE-2. And if either one of it gets called, the loader shows on both the pages as its using 1 State ( API_IN_PROCESS ) to show a SPINNER/LOADER
I don't want to create separate states like this ( API_ONE_IN_PROCESS ) and ( API_TWO_IN_PROCESS ) because ones the project grows It may have 10s of pages and its not perfect to handle this issue.
Looking for a solution where the spinner is shown only in specific page where API is called.
As a suggestion, you can add one more state called EngagedPageIndex and update it when a page is engaged with API by page index (or identifier). So, you can control the Spinner/Loader by checking both of API_IN_PROCESS and EngagedPageIndex states for each page.
I have implemented infinite scroll on a project that is using React Query library.
So far so good. Everything works as expected using the useInfiniteScroll hook
One issue that I am encountering is the caching mechanism of this library.
If I query for a resource, ex: GET /posts/, will trigger a GET /posts/?page=0, scroll a bit down, get the next results, GET /posts/?page=1 which is totally fine. If I add search parameter to the page will do a GET /posts/?filter=someValue&page=0. All fine... but when I remove the filter from the search it will automatically do GET /posts/?page=0 & GET /posts/?page=1
A solution is to remove the query from the cache using the remove() method from the query itself. But this means that I have to manually do it for each query.
I would like to get a better solution that will cover all cases. I have a queryWrapper where I want to handle this.
I tried using the queryClient instances invalidateQueries and resetQueries but none seems to be able to remove it from the cache...
In the examples below I keep a ref for the params, if they are changed I can trigger the query to reset via useLayoutEffect hook. This part works as expected
invalidateQueries attempt
queryClient.invalidateQueries(
[queryKey, JSON.stringify(paramsRef.current)],
{
exact: true,
refetchActive: false,
refetchInactive: false
},
{ cancelRefetch: true }
);
resetQueries attempt
queryClient
.resetQueries([queryKey, JSON.stringify(paramsRef.current)], {
refetchPage: (page, index) => index === 0
})
I even tried the queryClient.clear() method which should remove all existing queries from the cache but still the page number somehow remains cached... I access the queryClient using useQueryClient hook. If I inspect it, I can see the queries inside.
Can someone please help me to sort this cache issue
Thanks!
but when I remove the filter from the search it will automatically do GET /posts/?page=0 & GET /posts/?page=1
This is the default react-query refetching behaviour: An infinite query only has one cache entry, with multiple pages. When a refetch happens, all currently visible pages will be refetched. This is documented here.
This is necessary for consistency, because if for example one entry was removed from page 1, and we wouldn't refetch page 2, the first entry on page 2 (old) would be equal to the last entry of page 1 (new).
Now the real question is, do you want a refetch or not when the filter changes? If not, then setting a staleTime would be the best solution. If you do want a refetch, refetching all pages is the safest option. Otherwise, you can try to remove all pages but the first one with queryClient.setQueryData when your query unmounts. react-query won't do that automatically because why would we delete data that the user has scrolled down to to see already.
Also note that for imperative refetches, like invalidateQueries, you have the option to pass a refetchPage function, where you can return a boolean for each page to indicate if it should be refetched or not. This is helpful if you only update one item and only want to refetch the page where this item resides. This is documented here.
I have a problem with DataTable and lazy loading.
When I activate the lazy loading paramater (which i can't remove because the request from the api is too big) the filtering and sorting does not work when the lazy loading is activated. I understand why it works like that, but I really have no idea how to fix it.
If you have any solutions I take it beacause I'm really stuck here :)
link to codesandbox -> https://codesandbox.io/s/datatable-t92wk
I made some modifications with the base exemple in primereact like adding lazy loading, removing paggination and replace it by virtual scrolling. I also made a modification with the filtering but I think that what I did is not really correct, but it works in that case : it stops the lazy variable and therefore I can use lazy loading.
What I would love to do is to sort already loaded data in the table :)
Thank you
Had the same issue. Apparently you can't use filtering with lazy loading mode (link). Makes sense really.
For sorting, you could pass an onSort function and everytime a sort event happens (i.e: user clicks on the column header), you can send back a DB request.
const onSort = (e) => {
// use e.sortField and e.sortOrder to send a DB request,
}
<DataTable onSort={onSort} ... // rest of the stuff />
Let's say my app is a list of many items. There's a lot of items so I don't want to include all the items in the redux state.
When a user visits me at myapp.com/item/:itemId, I want to display the selected item. Currently I make an api call in componentDidMount to fetch the item and store the response in myReduxState.selectedItem. However, this shows the user and unfinished page until the api call finishes.
Is there any way I can get around this?
The pattern I tend to follow is to have a state of fetching being tracked in the redux state. Once the api resolves you just make sure the state is set correctly and then in your render methods use that to determine what you are rendering.
render() {
if (this.state.fetching) {
return <div> // put whatever you want here, maybe a loading component?</div>
}
return (
// put the regular content you would put for when the api call finishes and have the data you need
)
}
I solved this problem by making the creating the state on the server side. I get the itemId from the url in my express route and get the details of the specific item. I use this to create the state and pass it to the front-end.
I need to implement infinity scroll features for fixed data table.
I checked API doc, there is no events dispatched when user scroll to the end of the table. The only seemly helpful event is onScrollEnd, but that event gives me back scrollX and scrollY.
ScrollY is pretty huge, I don't know how to use this number to detect user is scrolling near the end.
Can anyone tell me how I can implement infinity scroll feature using fixed data table?
Thanks
It is a shame that such component does not have proper API for infinite scroll.
The solution is this (but it is ugly):
The onScrollEnd() returns you a scrollY value. You need to persist this value in component state, e.g. this.state.scroll. On each onScrollEnd, you have to check for equality:
this.state.scroll === nextState.scroll && nextState.scroll !== 0 // you dont want to load dada on scrollTop.
If this is true, then you can load additional data, update your store or what you have, and re-render the component.
BIG PROBLEM: the onScrollEnd() function is very very slow :( Maybe do debouncing/throttling?