denoland / fresh

The next-gen web framework.
https://fresh.deno.dev
MIT License
12.67k stars 654 forks source link

Testing Story: Forever Scroll (How to hydrate loaded markup?) #1072

Open digitaldesigndj opened 1 year ago

digitaldesigndj commented 1 year ago

I would like to load some islands dynamically. The Roadmap #563 mentions a couple things long term.

These directly affect how something like a forever scroll case would be implemented. I think forever scroll is a great test case to study to see how this API is going to look. Keeping it simple, a post with a Date island is loaded a number of times (say 7) into a div. When the user scrolls I want to load a new set of posts. I could do this with a mega island, but is there a way to keep it uhh... "more fresh"?

565 starts to allow lazy loading. But how would I go about having an island load more islands?

digitaldesigndj commented 1 year ago

A Scenario:

I have an existing post type and I load 7 per page. Each Post (a server side component) has a Reaction and LocalDateTime Island. There are pagination links rendered if necessary at the bottom of each page. I want to turn the "Load More" link into an Island. It should load right away and use JS to detect when it scrolls into view.

Once the Island is in view, it should load the 7 more posts each with 2 islands. Then it can replace itself with the new posts in the DOM.

Obviously the Post component now has to be rendered client side. That's new, my brain says move it into /components but I don't see where to go from there. And I'm not really sure that's anything but a convention.

I also need to initialize the Islands in the server side component. That's where it really starts to get beyond my grasp.

I think there are a lot more use cases for this kind of API, but I think this one stands out. It's a pattern that worked pretty well with JQuery and the DOM. Is there a way we can keep Fresh fresh while enabling this recursive loading of islands?

digitaldesigndj commented 1 year ago

TLDR; too long dear reddit

Please let me load Components with Islands in them using this system? That would be 👍

digitaldesigndj commented 1 year ago

With the back in the day example, I could grab the markup by loading the next page, but the bit of hydrating the interactions would be wired up manually. So maybe what I am grasping for here is an Island hydration API that could work from markup?

IDK if that is a good idea.

A better architecture might be the cure here, or not.

Just as an example. the pagination could be a big island in the first place. Loading the first 7 posts via whatever ajax methods the forever scroll paginator is going to use. That's probably closer to what the Island Hydration architecture demands, but I still want to instantiate some islands dynamically on the paged content.

nesterow commented 1 year ago

I think you want to use an IntersectionObserver in an island. Once the observed node is visible you can load more data and add it to the list of the posts. So on the server side you would initally load constant number of posts, then on the client your island would load more untill the node is invisible or the number of returtned posts is less than limit.

I use an intersection observer to lazy-hydrate islands, this is where the lazy loaded islands would be useful to save some bytes. Examples: LazyHydrate Component | Lazy Island Test

I don't know what they meant by "a first class type safe data fetching system for islands" though :)

digitaldesigndj commented 1 year ago

You inspired me. Here is actual code that works like I said. It loads the elements into the DOM (using InstersectionObserver) but falls short at the hydration step. I don't use Fresh at all to get my elements into the DOM, just some nilla JS.

https://github.com/Hyprtxt/linceo.club/blob/foreverscroll/islands/ForeverScrollLoader.jsx

(edit: The link is updated and the feature is all there now, except...)

The actual problem: If only I could get the islands hydrated. In my head I think the code we need is all already there, I just have to call it somehow.

digitaldesigndj commented 1 year ago

I added the signals to make it all work and realized it's good enough to post. The reactions are broken on the loaded posts, but most of my users (grandparents) only browse, and it works for that just great.

https://linceo.club/gram

If you scroll all the way, I have not hidden the pagination link, and you can see that my query string pagination is still intact (I mean it powers the forever scroll, but still) and it's spider/accessibility (I hope) friendly too.

Edit: This is still broken, its good enough, but I wish I could figure out how to hydrate my islands.