Security News
The Push to Ban Ransom Payments Is Gaining Momentum
Ransomware costs victims an estimated $30 billion per year and has gotten so out of control that global support for banning payments is gaining momentum.
svelte-infinite
Advanced tools
Readme
Svelte Infinite Loader designed and rebuilt specifically for use in Svelte 5 with runes
✨ Flexible
⏰ Infinite Loop Detection
📣 Control Loader State
🔎 IntersectionObserver
based
🧑🔧 Demo: svelte-5-infinite.vercel.app
svelte-infinite
npm install svelte-infinite
pnpm install svelte-infinite
yarn add svelte-infinite
InfiniteLoader
and stateChanger
from svelte-infinite
<script lang="ts">
import { InfiniteLoader, stateChanger } from "svelte-infinite"
const allItems = $state([])
const loadMore = async () => {
const res = fetch("...")
const data = await jes.json()
allItems.push(...data)
stateChanger.loaded()
}
</script>
<InfiniteLoader triggerLoad={loadMore}>
{#each allItems as user (user.id)}
<div>{user.name}</div>
{/each}
</InfiniteLoader>
The component should wrap your list of items, and stateChanger
should be used in your triggerLoad
function (and/or elsewhere) to interact with the internal state of the Loader component. You tell it whether you're out of data, ran into an error, etc.
See the example below and in this repository for more details.
<script lang="ts">
import { InfiniteLoader, stateChanger } from "svelte-infinite"
import UserCard from "$components/UserCard.svelte"
const LOAD_LIMIT = 20
const allItems = $state<{ id: number, body: string }[]>($page.data.items)
let pageNumber = $state(1)
// 1. You'll have to pass the InfiniteLoader component a load function
// to its `triggerLoad` prop.
const loadMore = async () => {
// This is a relatively straight-forward load function with support for pagination
try {
pageNumber += 1
const limit = String(LOAD_LIMIT)
const skip = String(LOAD_LIMIT * (pageNumber - 1))
// If there are less results on the first page (page.server loaded data)
// than the limit, don't keep trying to fetch more. We're done.
if (allItems.length < LOAD_LIMIT) {
stateChanger.complete()
return
}
const searchParams = new URLSearchParams({ limit, skip })
// Execute the API call to grab more data
const dataResponse = await fetch(`/api/data?${searchParams}`)
// Ideally, like most paginated endpoints, this should return the data
// you've requested for your page, as well as the total amount of data
// available to page through
if (!dataResponse.ok) {
stateChanger.error()
// On errors, set the pageNumber back so we can retry
// that page's data on the next 'loadMore' attempt
pageNumber -= 1
return
}
const data = await dataResponse.json()
// If we've received data, push it to the reactive state variable
// rendering our items inside the `<InfiniteLoader />` below.
if (data.items.length) {
allItems.push(...data.items)
}
// If there are more (or equal) number of items loaded as are totally available
// from the API, don't keep trying to fetch more. We're done.
if (allItems.length >= data.totalCount) {
stateChanger.complete()
} else {
stateChanger.loaded()
}
} catch (error) {
console.error(error)
stateChanger.error()
pageNumber -= 1
}
}
</script>
<main class="container">
<!-- 2. Here you wrap your items with the InfiniteLoader component -->
<InfiniteLoader triggerLoad={loadMore}>
{#each allItems as user (user.id)}
<UserCard {user} />
{/each}
<!-- There are a few optional slots for customizing what is shown at the bottom
of the scroller in various states, see README.md for more details -->
<div slot="loading">Loading...</div>
<div slot="no-data">Thats it, no more users left!</div>
</InfiniteLoader>
</main>
</script>
The InfiniteLoader
component is a wrapper around your items, which will trigger the triggerLoad
function when the user scrolls to the bottom of the list.
However, there is also a stateChanger
export which you should use to interact with the internal state of the loader. For example, if your fetch
call errored, or you've reached the maximum number of items, etc. See the loadMore
function above or the example application in /src/routes
in this repository.
The stateChanger
import is an object with 4 methods on it:
stateChanger.loaded()
stateChanger.error()
InfiniteLoader
to render a "Retry" button by default, or the error
slot.stateChanger.complete()
no-data
slot.stateChanger.reset()
InfiniteLoader
to its initial state, for example if there is a search input tied to your infinite list and the user enters a new query.triggerLoad: () => Promise<void>
- required
intersectionOptions:
IntersectionObserverInit
= { rootMargin: "0px 0px 200px 0px" }
- optional
IntersectionObserver
instance. See MDN for more details. The default rootMargin
value will cause the target to intersect 200px earlier and trigger the loadMore
function before it actually intersects with the root element (window by default). This has the effect of beginning to load the next page of data before the user has actually reached the current bottom of the list, making the experience feel more smooth.root
option, if your scroll container is not the window.loopTimeout: number = 1000
- optional
loopMaxCalls
is reached within this duration (in milliseconds), a cool down period is triggered.loopMaxCalls: number = 5
- optional
triggerLoad
function within timeout which should trigger cool down period.loading
triggerLoad
and waiting on a response.no-results
no-data
stateChanger.complete()
is called, indicating we've fetched and displayed all available data.error
stateChanger.error()
has been called. The slot has an attemptLoad
prop passed to it which is just the internal triggerLoad
function, designed for a "Retry" button or similar.MIT
FAQs
Infinite scroll for Svelte 5 with Runes
We found that svelte-infinite demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Ransomware costs victims an estimated $30 billion per year and has gotten so out of control that global support for banning payments is gaining momentum.
Application Security
New SEC disclosure rules aim to enforce timely cyber incident reporting, but fear of job loss and inadequate resources lead to significant underreporting.
Security News
The Python Software Foundation has secured a 5-year sponsorship from Fastly that supports PSF's activities and events, most notably the security and reliability of the Python Package Index (PyPI).