-
-
Notifications
You must be signed in to change notification settings - Fork 303
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add reverse support #400
Add reverse support #400
Conversation
Im unclear why the package.json changes are here. Isnt 18 the latest? |
shouldScroll = instance.options.reverse ? scrollY - prevY : prevY - scrollY; | ||
} | ||
|
||
if (shouldScroll) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this be a more clear boolean comparison, like if (shouldScroll) > 0
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think it should, it seems that the idea is to scroll in either direction if needed.
@@ -341,7 +355,7 @@ export class Virtualizer<TScrollElement = unknown, TItemElement = unknown> { | |||
|
|||
this.unsubs.push( | |||
this.options.observeElementOffset(this, (offset) => { | |||
this.scrollOffset = offset | |||
this.scrollOffset = offset; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
did you mean to add this ;
?
Seems like the use of ; is pretty inconsistent throughout
let end | ||
if (reverse) { | ||
end = measurements[i - 1] | ||
? measurements[i - 1]!.start |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Generally feel a bit hesitant about using !
.. is there another way we can write this? Maybe wrap with an if (measurements[i -1])
and then add some kind of error case?
getTotalSize = () => { | ||
let size | ||
if (this.options.reverse) { | ||
size = ((this.getMeasurements()[this.options.count - 1]?.start * -1) || |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why times -1 here?
size = ((this.getMeasurements()[this.options.count - 1]?.start * -1) || | ||
this.options.paddingStart) + this.options.paddingEnd |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This won't compile because you may be calculating undefined * -1
. See below:
size = ((this.getMeasurements()[this.options.count - 1]?.start * -1) || | |
this.options.paddingStart) + this.options.paddingEnd | |
const measurements = this.getMeasurements()[this.options.count - 1] | |
size = (measurements ? (measurements.start * -1) : this.options.paddingStart) + this.options.paddingEnd |
Also, should you switch paddingStart
and paddingEnd
since they are reversed?
Hey @bradley do you use virtual for a chat application? If yes, does it work well? I'm looking for a chat/list component and I have tried many components, but no one works well with dynamic elements, which could be appended to top or/and bottom. |
Looks quite good. Will it be merged? |
@bradley, can you resolve the conflicts? |
Hi, had a look what we can do on reverse support using current impl, interesting part is the sync scroll when we prepend items on top and don't unmount current items. Got something like this https://codesandbox.io/s/lively-leaf-4mext1?file=/pages/index.js Basic the idea is to return prev items till the scroll will sync. Question is, when to reset the value that controls rendering prev items 🤔 |
@piecyk your codesandbox looks great. What do you mean when you say "scroll will sync"? |
@jonathanbutler7 when prepending items we need to preserve current items, this basic means that we need to adjust current scroll position by elements that was added. Also till the scroll happens we need to render same items, that's the I would go more into that direction, making the core more flexible rather adding more complexity 🤔 |
Hi @piecyk, I appreciate you taking the initiative to make the core more adaptable and providing a sandbox example. This feature is not included by default in other packages, so adding support for it natively rather than requiring users to implement it will be very well received and may encourage more people to adopt the @tanstack/react-virtual library. |
Kinda looks like we already have native support, the trick is to update scroll offset in same time when new items are prepend https://codesandbox.io/s/beautiful-meninsky-fr6csu?file=/pages/index.js |
@predam @piecyk you both make good points. Since the "chat" use case is prevalent, it definitely seems like a big value-add for this library to support it in one way or another. It seems that there is a) desire from the user base and b) support from the maintainers. I see two possible approaches:
What do you guys think? |
Yes, that's are valid points 👍 Thanks @jonathanbutler7 to be part of the discusion 👍 Just to be clear, i'm not against adding Overall by design virtual should be low level implementation, allowing to build users any ui on top of if. Looking on @bradley example users still need to add specific css to support the Comparing it to latest example, to support reverse infinite scroll, user need to revers the index and in case when items are prepend sync scroll. |
I would love some documentation added for this! I've been playing with the sandbox today and I get the general idea, but feel foggy on a few things. So far I have not been able to successfully apply this approach to my own codebase.
Yep, that's the exact issue I'm facing. With chat you need to be able to prepend the chat history as a user scrolls up, but still be able to append new messages. Thanks so much for looking into this, btw, @piecyk |
From my point of view, |
In the end to have bi-directional infinite list we just need to sync scroll in case of prepend https://codesandbox.io/s/infinite-scroll-both-c08vxk?file=/pages/index.js and that's all. |
@piecyk some interesting thoughts to keep in mind when thinking of something like chat:
Most of the issues I'm having are around scrolling properly to the last item, either initially or as new messages come in, due to the variable size of the items. |
@lexahall let's add an example to the repo, can you share some example of chat app that we can work on? |
In my experience, not unconditionally. It depends on where the user is. If the user is a little bit above (iirc we used around 200px), then you will usually show "new message" label instead of direct scrolling. Probably, it need an imperative way to scroll to the specific message with top or bottom alignment. |
@piecyk, like a codesandbox example? |
@piecyk I'll work on a sandbox, but I have a couple questions about your implementation I want to make sure I understand. I see that you're adjusting the scrollOffset when new items are fetched using: const nextOffset =
virtualizerRef.current.scrollOffset + pageSize * itemSize;
virtualizerRef.current.scrollOffset = nextOffset;
virtualizerRef.current.calculateRange();
virtualizerRef.current.scrollToOffset(nextOffset, { align: "start" }); For the pageSize * itemSize calculation, this seems very dependent upone knowing the item size. Or at least having a very good estimate. What about cases where the items can be very different sizes? Wont this cause scroll issues? What does |
|
This PR is outdated and probably needs a fresh perspective. |
Does anyone have a Vue sample for the reverse infinite scroll feature? |
I'd love one in Svelte as well |
See sandbox for how to use: https://codesandbox.io/s/react-virtual-reverse-scroll-infinite-example-pf73zb