Breezy
main
main
  • README
  • Code of conduct
  • Contributing Guide
  • Changelog
  • Security Policy
  • docs
    • configuration
    • Cross cutting concerns
    • deferments
    • Demo Application
    • Digging
    • Overview
    • Installation
    • NavigationContext
    • The page response
    • Rails utils
    • The store shape
    • Requests
    • Tutorial
    • The return of Rails UJS
    • recipes
      • Infinite scroll
      • Modals
      • progress-bar
      • Shopping cart
      • SPA (Single Page Application) Pagination
      • Server-Side Rendering
      • Replicating Turbo behavior
      • Usage with vite
    • Modules
      • Functions
      • Functions
      • index
      • types.actions
      • types
      • Interfaces
Powered by GitBook
On this page

Was this helpful?

  1. docs
  2. recipes

Infinite scroll

PreviousrecipesNextModals

Last updated 2 months ago

Was this helpful?

In this recipe, we'll add infinite scroll to our application. Superglue doesn't have an infinite scroll component, but it has tools that make it easy to work with React's ecosystem.

Lets begin by adding react-infinite-scroll-hook

yarn add react-infinite-scroll-hook

And continue off from our recipe.

!!! tip We'll use the beforeSave callback to modify the payload before superglue saves it to the store. This callback is an option for both visit and remote functions. See the for more details.

// app/views/posts/index.js

import React from 'react'
- import {useContent} from '@thoughtbot/superglue'
+ import {useContent, NavigationContext} from '@thoughtbot/superglue'
import PostList from './PostList'
import Header from './Header'
+ import useInfiniteScroll from 'react-infinite-scroll-hook';

export default PostIndex = () => {
  const {
    posts,
    header,
    pathToNextPage,
    pathToPrevPage
  } = useContent()

+ const { remote, pageKey } = useContext(NavigationContext)
+ const { loading, setLoading } = useState(false)
+ const hasNextPage = !!pathToNextPage
+
+ const beforeSave = (prevPage, receivedPage) => {
+   const prevPosts = prevPage.data.posts
+   const receivedPosts = receivedPage.data.posts
+   receivedPage.data.posts = prevPosts + receivedPosts
+
+   return receivedPage
+ }
+
+ const loadMore = () => {
+   setLoading(true)
+   remote(pathToNextPage, {pageKey, beforeSave})
+     .then(() => setLoading(false))
+ }
+
+ const [sentryRef] = useInfiniteScroll({
+   loading,
+   hasNextPage,
+   onLoadMore: loadMore,
+ });

  return (
    <>
      <Header {...header}/>
      <div>
        {
          posts.list.map(({id, body}) => (
            <p key={id}>{body}</p>
          ))
        }
+       {(loading || hasNextPage) && (
+         <p ref={sentryRef}>
+           loading
+         </p>
+       )}
      </div>
-     {pathToPrevPage && <a href={pathToPrevPage} data-sg-visit>Prev Page</a>}
-     {pathToNextPage && <a href={pathToNextPage} data-sg-visit>Next Page</a>}
    </>
  )
}
pagination
beforeSave reference