-
-
Notifications
You must be signed in to change notification settings - Fork 3.1k
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
Infinite scroll in reverse order #212
Comments
So the missing part is right now the ability to scroll up (beginning of a vertical list) and request previous rows. To go more technically:
|
This means that startIndex in InfiniteLoader can actually become a negative number. |
Hey @kof, Reading this feature request, I wonder if you've considered doing something like...
I think that would work as you've described? If not, I think it may be appropriate for you to create a fork of |
I have created my IniniteLoader based on the original one. However I can't imagine this is an edge case. This is nothing else but a very long list where you jump in the middle of it and want to go back. Imagine google search with 1000000 results and you can't load them on. Now you are on a page x and want to go back. With pagination you just click on the previous page number. Exactly the same is here. |
This was my first idea and resulted in junked scrolling, because:
|
It doesn't seem like the same thing to me @kof. Google doesn't show you the middle results as page 0 (or 1). Everything component and utility in react-virtualized is written to work with a list or array- things that don't make sense when we start talking about negative indexes. Despite what you say, yours is the first request I've ever received to support negative indexes. |
Well imagine you got a link to the page 100. You don't load all the results before, right?
Well maybe negative indexes isn't the right approach anyways. My interest is to unlock the use case. How is a different question. |
I mentioned a potential workaround using
There are some limitations of how react-virtualized can be used. That's because I've written 99% of the code and I only have so much time. Feel free to propose (and submit) a new HOC if you think there's an alternative to |
additionally |
not exactly right, we might render less than we load, which means I need to calculate height of newly-rendered rows. |
So implement your own
That's not how RV components work. To render (and position) row N you need to have measured rows 0...N. |
I don't think there's any action for me to take on this issue at the moment so I'm going to close it. We can continue discussion though- I just like to keep the issues list pruned. |
@kof I'm needing to do the same kind of thing. Chat...which should really be bottom to top scrolling. I'm curious if you ever found a workable solution...I managed to get variable height rows working by pre-rendering in It works fine if I just download all messages in a conversation up front. I'm not sure at what point this will start to be a performance concern. It would be ideal if I could structure my array newest-to-oldest and just have the RV component render bottom to top. No idea what that would take. Anyway, I was just curious if you had suggestions. |
I have one, but I still didn't come to make it ready for open source. |
Also my requirement is to load infinite amount of messages and also being able to start in the middle of that stream. I have implemented a bunch of components to do that. |
No worries...and thanks for the response. I think for now I may just load the last 100 (or so) messages, and then offer a button to load all (slowly) if need be. |
Another example of the same bi-directional scrolling need: calendars. |
The biggest issue I can see- other than the added complexity from additional forking behavior- would be with dynamically measured content (eg a chat list using react-virtualized has been optimized to defer measuring cells until needed for better performance. If you have a list of 1,000,000,000 rows, but only the first 15 are visible, it only measures the first 15 and uses an estimated height for the rest. If you scroll down to rows 50...64, it will measure 15...64 but then continue using the estimated height for 65+. The reason it measures rows 15...64 if a user jumps from 0...14 to 50...64 is a bit complicated to explain. Basically once react-virtualized measures a certain cell- its size and position is cached (unless certain properties change which tell it to clear the cache) to avoid having to recalculate it later. (This is another performance tweak.) If we were to continue using estimated row heights for rows 15...64, then as a user scrolled up from row 50- we would have to run through every row after the current row and slightly adjust their position to match their newly-calculated position. (This gets very expensive if a user jumps to the end of a list and then scrolls to the beginning.) Now, some caveats:
I have thought a little about doing this. I may even open an issue for it now while I'm thinking about it. Anyway, the reason I mention this long-winded explanation is- displaying items in reverse order makes this issue much more prevalent. Every time you add a new item, it pushes everything else down and requires us to update offsets. With the current implementation- this would be very expensive if a user were scrolled to the end of a long chat list. Edit: I've created issue #309 for this. |
I believe I understand the issue. Absolutely positioning a row requires knowledge of the distance from the It seemed like this might be as simple as absolutely positioning from I'm sure that wouldn't work either. Even Google Hangouts web client is janky when scrolling up. This must just be something that just doesn't work well in web. The one thing I noticed about Hangouts though...they use Thanks again for the conversation on this. I'm not sure if this is the best place for it or if a solution is possible, but the attention is certainly appreciated. |
Yes. I can estimate the position based on the number of rows before it and their estimated size, but if the actual size differs, it can cause things to be "janky" (rows might pop in or out of visibility unexpectedly as we replace the estimates with real measurements).
I think this would have the same UX behavior while scrolling. (If real measurements differ from estimated ones, things would look broken. The more they differ- the more they would look broken.
This is a possibility I haven't considered much. Maybe there's something there. I'm not sure. I think it might still be a little janky because I think we would have to essentially assume all rows (or columns) are the same size and then dynamically shift them around a bit faster (or slower) as a user scrolls based on their actual size. This might make it look like the scrolling speed is inconsistent if you have a bunch of short rows followed by a couple of really tall rows. |
To those of you working on chat boxes, how do you start your VirtualScroll from the bottom? I've tried |
We ended up going with a non-virtualized lazy-loading div. I load the most recent N messages from a conversation and then use componentDidUpdate to scroll to the bottom of the div. Then, I use a scroll event handler to fetch more messages when the user scrolls up. The tricky part is that I have to figure out the height of the additional messages after loading more so that I can set the scrollTop back to the same message. This was simple enough in componentDidUpdate and results in surprisingly smooth scroll performance:
The nice thing as that I don't have to calculate/cache heights to render. On the other hand, if a user ever wants to scroll to the top of a very long conversation, they could experience some performance issues. It's something that I don't think most users will ever notice, and it should work nicely for us - at least until we figure out a way to virtualize. |
I'm in need of an infinite load chat solution as well. Even just an easy way to have the messages list (1) start at the bottom and (2) have scrolling up trigger the loading of more messages would be nice. |
This should be possible using the |
This did work: I'll try out InfiniteLoader for the jit loading. |
@bvaughn do you know how I can go about triggering loadMoreRows on scroll up? |
Should just happen automatically. |
Initial Using |
@bvaughn I'm working on a similar case, where the loadMoreRows is not triggered. I have an infinite list showing items in reverse order (I couldn't make the list to actually reverse, might be related to #610) and the loading indicator always stays at index 0.
|
If you can provide a small repro case, I can take a look. Better yet, a PR with a failing unit test and then a fix. 😄 |
I created a pen to reproduce it but I was able to make it work by using a threshold of 1. You can see the pen here if you want |
|
Yes, I was able to make it work, but only using the Also if you preload data, in |
As I mentioned, it works for me even if I increase the threshold prop |
Loading data on will-mount is not a good idea b'c of upcoming React async changes. (It will be possible for will-update or will-mount to be fired without actually committing anything to the DOM, so side effects should be avoided for those methods.) As for the bug you're seeing that I'm not, I'm not sure what to tell you. If I can't repro it (and I can't) then I can't be of much help. Try posting on Stack Overflow or somewhere similar? |
So if cWM is not the right way, what'd be the best approach to prevent an empty list when entering a screen? Any suggestions? |
It's hard to answer this generically. I just wanted to point out that side effects like loading data aren't recommended in any of the will* lifecycle methods b'c they might be run multiple times, or aborted before actually committing anything to the DOM. Here's a cheatsheet that lists which methods are safe for side effects. If it's possible to load the data outside of your list-rendering component, and just pass it in as a prop, this could allow you to avoid using a lifecycle method. Maybe it's possible to load an initial "page" of data outside of React entirely depending on how your application is initialized. I don't know enough about it to answer. |
Thanks @bvaughn for the quick response! BTW, I just tested the pen on Safari, and I first though it was working without specifying the threshold but then I realized it was not using the latest version of the pen. Refreshed and now I see the same as in chrome. Just to let you know, but I understand it you can't reproduce it, I'll try to dig deeper to see if I can find anything else. Thanks anyway |
@kof |
Did anyone manage to implement a reverse ordered (chat style) scroll bottom to top working? it seems the use case is popping up more so for that style of chat with few clear working examples. Irksome having got a dynamic height top to bottom working already for another section of our app we're now struggling with a chat box that is pinned to the most recent (bottom msg) and scrolls up for the history. |
I have this use case as well. An example of this would be a huge help. |
hi, do we have a solution for that case? I need to loadMoreRow on scroll up |
After a lot of researching I found this amazing project: React Virtuoso. It's perfect for this exact use case: a reverse ordered chat style scroll bottom to top. I've been using it and it works like a charm. Take a look to this example: https://virtuoso.dev/prepend-items/ |
@davidivad96 do you have any public demo showing how you use it for a chat application? Thank you!! |
@jan-wilhelm try something like: <Virtuoso
data={state.contents}
followOutput="smooth"
alignToBottom={true}
overscan={10000}
itemContent={(index, message): React.ReactElement => { But well, I experience some glitches. |
Did you manage to solve these glitches? I'm facing some too. |
Unfortunately, not. I reduced the amount of content, but it's rather a workaround. |
Hi, first about my use case:
I am building a chat app. Which means it is essentially important to:
This means that the list we are going to render is potentially just a fragment of a very long list, there are rows after what we have got and there are rows before.
We need to be able to scroll up and load previous rows as we go, as well as to scroll down and load next rows.
The text was updated successfully, but these errors were encountered: