Skip to content

Commit c8ce22d

Browse files
authored
feat: refactor to move instantiating LoaderState to the user (#12)
1 parent bb1dbb8 commit c8ce22d

File tree

6 files changed

+28
-21
lines changed

6 files changed

+28
-21
lines changed

README.md

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,11 @@
1414

1515
> Svelte Infinite Loader designed and rebuilt specifically for use with **Svelte 5**
1616
17-
✨ Flexible
18-
⏰ Infinite Loop Detection
19-
📣 Control Loader State
20-
🔎 `IntersectionObserver` based
21-
🔥 Using Runes and Snippets
17+
✨ Flexible
18+
⏰ Infinite Loop Detection
19+
📣 Control Loader State
20+
🔎 `IntersectionObserver` based
21+
🔥 Using Runes and Snippets
2222
🧑‍🔧 **Demo**: [svelte-5-infinite.vercel.app](https://svelte-5-infinite.vercel.app)
2323

2424
## 🏗️ Getting Started
@@ -31,12 +31,13 @@ pnpm install svelte-infinite
3131
yarn add svelte-infinite
3232
```
3333

34-
2. Import both `InfiniteLoader` and `loaderState` from `svelte-infinite`
34+
2. Import both `InfiniteLoader` and `LoaderState` from `svelte-infinite`
3535

3636
```svelte
3737
<script lang="ts">
38-
import { InfiniteLoader, loaderState } from "svelte-infinite"
38+
import { InfiniteLoader, LoaderState } from "svelte-infinite"
3939
40+
const loaderState = new LoaderState()
4041
const allItems = $state([])
4142
4243
const loadMore = async () => {
@@ -47,7 +48,7 @@ yarn add svelte-infinite
4748
}
4849
</script>
4950
50-
<InfiniteLoader triggerLoad={loadMore}>
51+
<InfiniteLoader {loaderState} triggerLoad={loadMore}>
5152
{#each allItems as user (user.id)}
5253
<div>{user.name}</div>
5354
{/each}
@@ -61,10 +62,10 @@ This is a more realistic example use-case which includes a paginated data endpoi
6162
```svelte
6263
<script lang="ts">
6364
// +page.svelte
64-
65-
import { InfiniteLoader, loaderState } from "svelte-infinite"
65+
import { InfiniteLoader, LoaderState } from "svelte-infinite"
6666
import UserCard from "$components/UserCard.svelte"
6767
68+
const loaderState = new LoaderState()
6869
const LOAD_LIMIT = 20
6970
// Assume `$page.data.items` is the `+page.server.ts` server-side loaded
7071
// and rendered initial 20 items of the list
@@ -128,8 +129,7 @@ This is a more realistic example use-case which includes a paginated data endpoi
128129
<main class="container">
129130
130131
<!-- 2. Here you wrap your items with the InfiniteLoader component -->
131-
132-
<InfiniteLoader triggerLoad={loadMore}>
132+
<InfiniteLoader {loaderState} triggerLoad={loadMore}>
133133
{#each allItems as user (user.id)}
134134
<UserCard {user} />
135135
{/each}
@@ -153,7 +153,10 @@ This is a more realistic example use-case which includes a paginated data endpoi
153153

154154
This package consists of two parts, first the `InfiniteLoader` component which is a wrapper around your items. It will trigger whichever async function you've passed to the `triggerLoad` prop when the user scrolls to the bottom of the list.
155155

156-
Second, there is also a `loaderState` import 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. you can communicate that to the loader. The most basic usage example can be seen in the 'Getting Started' section above. A more complex example can be seen in the 'Example' section, and of course the application in `/src/routes/+page.svelte` in this repository also has a "real-world" usage example.
156+
Second, there is also a `LoaderState` class 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. you can communicate that to the loader. The most basic usage example can be seen in the 'Getting Started' section above. A more complex example can be seen in the 'Example' section, and of course the application in `/src/routes/+page.svelte` in this repository also has a "real world" usage example.
157+
158+
> [!WARNING]
159+
> As of `0.5.0` the `LoaderState` import is not an instance of the class, but the class itself. Meaning you'll need to instantiate it yourself with `new LoaderState()` per component instance. This gives the user more flexibility when trying to use multiple `svelte-infinite` instances per page, as well as resetting the state.
157160
158161
### `loaderState` Controller
159162

@@ -170,6 +173,8 @@ The `loaderState` controller has 4 methods on it. You should call these at the a
170173

171174
### `InfiniteLoader` Props
172175

176+
- `loaderState: LoaderState`
177+
- An instance of the `LoaderState` class.
173178
- `triggerLoad: () => Promise<void>` - **required**
174179
- The async function to call when we should attempt to load more data to show.
175180
- `intersectionOptions: `[`IntersectionObserverInit`](https://developer.mozilla.org/en-US/docs/Web/API/IntersectionObserver/IntersectionObserver#options)` = { rootMargin: "0px 0px 200px 0px" }` - optional

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
"email": "yo@ndo.dev",
77
"url": "https://ndo.dev"
88
},
9-
"version": "0.4.0",
9+
"version": "0.5.0",
1010
"license": "MIT",
1111
"homepage": "https://svelte-5-infinite.vercel.app",
1212
"keywords": [

src/lib/InfiniteLoader.svelte

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
<script lang="ts">
22
import { onMount, onDestroy, type Snippet } from "svelte"
3-
import { STATUS, loaderState } from "./loaderState.svelte"
3+
import { STATUS, LoaderState } from "./loaderState.svelte"
44
55
type InfiniteLoaderProps = {
66
triggerLoad: () => Promise<void>
77
loopTimeout?: number
88
loopDetectionTimeout?: number
99
loopMaxCalls?: number
1010
intersectionOptions?: Partial<IntersectionObserver>
11+
loaderState: LoaderState
1112
children: Snippet
1213
loading?: Snippet
1314
noResults?: Snippet
@@ -22,6 +23,7 @@
2223
loopDetectionTimeout = 2000,
2324
loopMaxCalls = 5,
2425
intersectionOptions = {},
26+
loaderState,
2527
children,
2628
loading: loadingSnippet,
2729
noResults: noResultsSnippet,

src/lib/index.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
import InfiniteLoader from "./InfiniteLoader.svelte"
2-
import { loaderState } from "./loaderState.svelte"
2+
import { LoaderState } from "./loaderState.svelte"
33

4-
export { InfiniteLoader, loaderState }
4+
export { InfiniteLoader, LoaderState }

src/lib/loaderState.svelte.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ export const STATUS = {
55
ERROR: "ERROR"
66
} as const
77

8-
class LoaderState {
8+
export class LoaderState {
99
isFirstLoad = $state(true)
1010
status = $state<keyof typeof STATUS>(STATUS.READY)
1111
mounted = $state(false)
@@ -26,5 +26,3 @@ class LoaderState {
2626
this.status = STATUS.ERROR
2727
}
2828
}
29-
30-
export const loaderState = new LoaderState()

src/routes/+page.svelte

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,9 @@
33
// import SvelteLogo from "$assets/SvelteLogo.svelte"
44
import { LOAD_LIMIT } from "$routes/lib/utils"
55
import UserCard from "$routes/lib/UserCard.svelte"
6-
import { InfiniteLoader, loaderState } from "$lib/index.js"
6+
import { InfiniteLoader, LoaderState } from "$lib/index.js"
77
8+
const loaderState = new LoaderState()
89
const allItems = $state<{ id: number; body: string }[]>($page.data.items)
910
let pageNumber = $state(1)
1011
let rootElement = $state<HTMLElement>()
@@ -69,6 +70,7 @@
6970
</span>
7071
</p>
7172
<InfiniteLoader
73+
{loaderState}
7274
triggerLoad={loadMore}
7375
loopDetectionTimeout={7500}
7476
intersectionOptions={{ root: rootElement, rootMargin: "0px 0px 500px 0px" }}

0 commit comments

Comments
 (0)