Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 2 additions & 18 deletions docs/guides/svelte/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,15 +58,7 @@ const Posts = new Collection({
reactivity: svelteReactivityAdapter,
});

let items = $state.raw([]);
$effect(() => {
const cursor = Posts.find({});
items = cursor.fetch();

return () => {
cursor.cleanup();
};
});
let items = $directive(Posts.find({}).fetch());
```

This code sets up a `Posts` collection and enables reactivity using Svelte’s built-in reactivity features.
Expand All @@ -84,15 +76,7 @@ Now let's create a component that lists posts and allows the user to add new one
reactivity: svelteReactivityAdapter,
});

let items = $state.raw([]);
$effect(() => {
const cursor = Posts.find({});
items = cursor.fetch();

return () => {
cursor.cleanup();
};
});
let items = $directive(Posts.find({}).fetch());
</script>

<button onclick={() => Posts.insert({ title: 'Post', author: 'Author' })}>
Expand Down
2 changes: 1 addition & 1 deletion docs/reactivity/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ For some libraries, it wasn't possible to implement a [`onDispose`](/reference/c
| [`sinuous`](/reference/sinuous/) | ✅ | ✅ | ❌ |
| [`Solid Signals`](/reference/solid/) | ✅ | ✅ | ❌ |
| [`sprae`](https://github.com/dy/sprae) (see [#858](https://github.com/maxnowack/signaldb/issues/858)) | ✅ | ❌ | ❌ |
| [`Svelte Runes`](/reference/svelte/) | ✅ | | ✅ |
| [`Svelte Runes`](/reference/svelte/) | ✅ | | ✅ |
| [`ulive`](https://github.com/kethan/ulive) | ❌ | - | - |
| [`usignal`](/reference/usignal/) | ✅ | ❌ | ❌ |
| [`Vue.js refs`](/reference/vue/) | ✅ | ❌ | ❌ |
13 changes: 1 addition & 12 deletions docs/reference/svelte/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,22 +34,11 @@ const Posts = new Collection({
reactivity: svelteReactivityAdapter,
});

let items = $state.raw([]);
$effect(() => {
const cursor = Posts.find({});
items = cursor.fetch();

return () => {
cursor.cleanup();
};
});
let items = $directive(Posts.find({}).fetch());
```

Reactivity adapter for usage with [Svelte 5](https://svelte.dev/).

The API of Svelte doesn't allow [automatic cleanup](/reference/core/createreactivityadapter/#ondispose-callback-void-dependency-dependency-optional).
With Svelte, you can return a function from your `$effect` that will be called on cleanup. Use this one to cleanup your cursors (see an example above).

In Svelte, reactivity is built into the very fabric of the framework, eliminating the need for manual change detection cycles. Svelte’s reactive declarations and writable stores automatically track and update state, ensuring that your UI remains consistently in sync with underlying data changes. When paired with SignalDB this natural reactivity is taken to the next level.

SignalDB seamlessly integrates with Svelte’s reactive model by emitting live data updates. As changes occur in SignalDB, those updates are immediately propagated to Svelte’s stores, triggering automatic re-rendering of affected components. This ensures that every part of your application reflects the most current data without any extra boilerplate or manual intervention.
Expand Down
4 changes: 4 additions & 0 deletions packages/reactivity-adapters/svelte/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Changed

* Add `onDispose` method to adapter and remove the need for manual cleanup (thanks @signalize!)

## [1.0.0] - 2025-03-27

### Added
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { it, expect } from 'vitest'
import { flushSync } from 'svelte'
import { Collection } from '@signaldb/core'
import svelteReactivityAdapter from '../index.svelte.ts'

Expand All @@ -8,23 +7,10 @@ it('should be reactive with svelte', async () => {
reactivity: svelteReactivityAdapter,
})

let count = $state(100)
const count = $derived(collection.find({}).count())

const cleanup = $effect.root(() => {
$effect(() => {
const cursor = collection.find({})
count = cursor.count()

return () => cursor.cleanup()
})
})

flushSync()
expect(count).to.equal(0)
collection.insert({ text: 'foo' })

flushSync()
expect(count).to.equal(1)

cleanup()
})
16 changes: 14 additions & 2 deletions packages/reactivity-adapters/svelte/index.svelte.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,29 @@ import { createReactivityAdapter } from '@signaldb/core'
const svelteReactivityAdapter = createReactivityAdapter({
create() {
let update: () => void
const subscribe = createSubscriber(u => update = u)
let cancel: () => void
const subscribe = createSubscriber((u) => {
update = u
return () => cancel()
})
return {
depend() {
subscribe()
},
notify() {
update()
if (update) {
update()
}
},
onStop(callback: () => void) {
cancel = callback
},
}
},
isInScope: () => !!$effect.tracking(),
onDispose(callback: () => void, { onStop }) {
onStop(callback)
},
})

export default svelteReactivityAdapter