Closed studentIvan closed 1 year ago
Can you test with this branch?
@petyosi thanks! Is good that you supporting the grid. I see the initialTopMostItemIndex there also. Without this feature its a bit complex to work with the endless reverse scrolling. Will test it soon.
stateChanged and restoreStateFrom also sounds crazy. Would be good to have it.
For people who stuck with such problem I can share my way to solve it with atTopStateChange
:
/**
* firstItemIndex allows to detect the numeric index of
* the first item in the rangeCallback (initialPosition)
*
* e.g. page=2, 28 items per page:
* firstItemIndex = (2 - 1) * 28 = 28
* intialPosition of the first range callback = 0 + 28 + 1 = 29
* so the item we see first is 29th item of this category items list
*/
const [firstItemIndex, setFirstItemIndex] = useState(
currentPage > 1 ? (currentPage - 1) * category.hitsPerPage : 0
);
/**
* we choose VirtuosoGrid because it allows us to use it both with desktop and mobile
*
* normal startReach + firstItemIndex reverse endless scrolling combination
* does not work with the VirtuosoGrid (since it has no firstItemIndex)
* @see https://virtuoso.dev/virtuoso-grid-api-reference/
*
* we using the hack here, what locks the page calculation and uses
* atTopStateChange event to detect atTop state (true by default)
*
* `scrollTopLock` is true by default when the page > 1
* we calc it by `firstItemIndex > 0` instead of `currentPage > 1` here
* since currentPage is a store value (dynamical) not a simple variable
* `firstItemIndex` is coming from the local state (like normal variable)
*
* so if the page > 1 and atTop is true (default scenario for any page > 1 first render)
* it calls the function "startReached" defined below
*
* scrollTopLock blocks the rangeCallback to reduce the risk of the currentPage changing
* "startReached" unlocks it normally right after the algolia data fetched
*
* since we use a hack - the page can have some layout shifts when calling with ?page=
* this is a payment of this hack
*
* normal user should not use ?page= directly, it mainly using by the crawlers
*/
const [scrollTopLock, setScrollTopLock] = useState(firstItemIndex > 0);
//...
const startReached = useCallback(() => {
const nextFirstItemIndex = firstItemIndex - category.hitsPerPage;
const prevPage = currentPage - 1;
if (prevPage >= 1) {
const setPrevPageProducts = (products: CategoryProduct[]) => {
dispatch({
type: ACTION.ADD_PAGE_PRODUCTS,
payload: { pageNumber: prevPage, products },
});
};
setTimeout(() => {
setPrevPageProducts(new Array(category.hitsPerPage));
setFirstItemIndex(() => (nextFirstItemIndex <= 0 ? 0 : nextFirstItemIndex));
// now we have the initialTopMostItemIndex
setTimeout(() => ref.current?.scrollToIndex(category.hitsPerPage + 2));
setTimeout(
() =>
requestProductsPage(prevPage)
.then(setPrevPageProducts)
.then(() => setScrollTopLock(false)),
80
);
}, 100);
}
}, [items, currentPage, category.totalPages]);
//..
<VirtuosoGrid
//...
atTopStateChange={
firstItemIndex > 0
? (atTop) => {
/** first init */
if (scrollTopLock && atTop) {
startReached();
}
if (!scrollTopLock && atTop && currentPage >= 2) {
/** free start reach */
setScrollTopLock(true);
startReached();
}
}
: undefined
}
/>
I ran into a similar issue with endReached
not working if initialItemCount
is set on Virtuoso
(sandbox example)
@sydneyjodon-wk what you have is not a valid configuration and not related to this thread. There are several threads that discuss a setup similar to yours.
@petyosi the stable branch (what is now the grid enhancement) still has this bug
@studentIvan this discussion has gone through several iterations. Can you please help me by reproducing the current problem you experience in a sandbox? Thanks.
Describe the bug
In the example code below everything works well
But if I add
startReached never fire, works well for endReached though. Thanks :)
Desktop (please complete the following information):