I have a factory function that creates a svelte store, which is bound to a Firebase Realtime object:
// $lib/firebase.ts
export function realtimeStore<Project>(path: string) {
let unsubscribe: () => void
const projectRef = ref(realtimeDB, path)
const { subscribe } = writable<Project | null>(null, (set) => {
unsubscribe = onValue(projectRef, (snapshot) => {
set((snapshot.val() as Project) ?? null)
})
return () => unsubscribe()
})
return {
subscribe,
set: (value: any) => {
return set(projectRef, value)
},
update: () => {},
}
}
export const project = realtimeStore('projectPath')
And in my components I can do stuff like:
<script lang="ts">
import { project } from '$lib/firebase'
$project.name = 'new name'
</script>
The problem comes when I need $project
to start pointing to another path, coming from $page.params.projectId
. I tried with a derived store, but it’s read only:
// $lib/firebase.ts
export const project: Readable<Project | null> = derived([selectedProjectId], ([$selectedProjectId], set) => {
if ($selectedProjectId) {
return realtimeStore<Project>($selectedProjectId).subscribe(set)
} else {
set(null)
}
})
// If I try to do $project.name = '...' from a component
// I get an error saying that project doesn't have a "set" function -
// the store is read only.
What is the best way to have a writable $project
that can also change the path to the realtime object?
2
Answers
As @parmer_110 suggested, added a
setPath
function torealtimeStore
:To use the store:
In
Svelte
, the stores using thewritable
function areread-write
stores, whereas the stores created using thederived
function areread-only
. For writable store change the path to the Firebase Realtime object.Now, your
project
store is writable and can beupdated
using theset
and update methods. Then you can change the path by unsubscribing from to the old path and subscribing to the new path. Update the imports and any other necessary code related to Firebase in thefirebase.ts
file.In your component, you can use the
$project
store and update its value accordingly:Above, whenever
$page.params.projectId
changes, it unsubscribes from the old path and sets the new path using thesetPath
method (which you need to add to yourcreateRealtimeStore
function). Theunsubscribe
function is called on component destruction to clean up any active subscriptions.Update
The
projectRef
is created inside the writable callback function,When the
setPath
method is called with a new path, it first unsubscribes from the previouspath
, updates thecurrentPath
value, and clears the store by callingset(null)
. The store will then be updated with the new data once the new path is set up.