LemmyNet / lemmy-ui

The official web app for lemmy.
https://join-lemmy.org/
GNU Affero General Public License v3.0
880 stars 335 forks source link

Remember scroll position when going back/forward #18

Closed Nutomic closed 3 years ago

Nutomic commented 4 years ago

Basically when you use the forward/back functions in your browser history, it scrolls you back to the page. This is pretty annoying if you want to continue going through the list of posts for example. It should remember the position instead (horizontal and vertical).

dessalines commented 4 years ago

This is a fairly difficult problem, as it requires storing the currently viewed item, or scroll position into browser storage, for every page, and on any page load, restoring that scroll position. I like the idea tho of doing it as a currently viewed item, since then new comments / posts could also use that on a resort, focusing you to what you were looking at.

richbowen commented 3 years ago

Probably a state management pattern/library could help here. The state of the page would be added to the store and then retrieved when going back in the browser history. This all goes away with a page refresh though.

MitchLillie commented 3 years ago

Isn't the root of the problem that fetchInitialData is called on every route navigation?

I know the philosophy is to have constantly fresh data, but if there was a way to merge the response from fetchInitialData into the previous (if any) response from the same, the components wouldn't be forced to completely re-mount, and then we would get the scroll position for free, since it's something browsers do out of the box.

dessalines commented 3 years ago

There's a couple things here, all stemming from lemmy being a live updating application.

  1. Your UI isn't receiving every update, only the ones for the "room" you're in, for example, if you're viewing a community page, you won't get updates from other communities. If you're viewing a posts page, you won't get updates from the front page, or other posts. This means that when navigating to a new place, we re-fetch data.
  2. Data persistence, or creating a global data store / state management, to me seems kinda pointless unless we are receiving every update... which wouldn't be a good idea for people's network bandwidth. So if we have to reload data when going to every new page anyway, what's the point? There's also memory concerns because these global data stores can get really big.
  3. This scroll issue is solved in a lot of chat programs by keeping timestamps of last read messages, and scrolling to that point. We can't do that here because of the tree view in comments, and because sorting can move things above and below anyway.
  4. I notice on my android reddit client (not sure about reddit web UI, I imagine its the same), the back button does remember scroll position.... but it doesn't load any new data, so its basically static content again. I def don't want this in lemmy, I want every page you view to be the present state of things, not a frozen historical snapshot.

fetchInitialData is called on every route navigation?

Its only called on initial page load, as an isomorphic http data call. IE

    if (this.isoData.path == this.context.router.route.match.url) {
      this.state.postRes = this.isoData.routeData[0];
      this.state.categories = this.isoData.routeData[1].categories;
      this.state.loading = false;

      if (isBrowser()) {
        this.fetchCrossPosts();
        if (this.state.commentId) {
          this.scrollCommentIntoView();
        }
      }
    } else {
      this.fetchPost();
      WebSocketService.Instance.send(wsClient.listCategories());
    }

fetchPost() (which does a websocket request) is only called when navigating to this route from other routes.

The simple and not smart way to do this, is to have browser storage keep a list of pages and scroll heights, which after the data loads, it scrolls to. Either that or find a way to figure out which object is "centered" / viewed, and then try to scroll to that if it exists. I don't have a good solution because its not static data.