Context
I'm using Svelte-Flow with Sevelte 5 for some project. To scale I want to have the object defining my node pushed to indexedDB. To keep it in sync and don't dodata handling twice, I want to sync my reactive object holding the nodes with the database.
<script>
let nodes = state.raw([]);
const some_new_node = {"type": "textNode", data: ["..."]}
async function addNode() {
// Let's make it simple and use dexie.js for interacting with indexedDB -> nodes is a store in a dexie-Database
const new_id = await db.nodes.add(some_new_node);
const some_new_node_with_id = {id: new_id, "type": ... };
nodes = [...nodes, some_new_node_with_id];
}
</script>
<button onclick:addNode></button>
<SvelteFlow bind:nodes> ... </SvelteFlow>
Problem
As I had to figure out like many more, Svelte 5 runes are not intended to work with async-functions due to race conditions. Thus, in the line with the await reactivity breaks and nodes is never updated.
So usually for async stuff like this I would now have to try out some solution using the {#await ...} syntax. The thing is: As I'm binding nodes and SvelteFlow expects for it's internals the given format, I'm kinda stuck how to solve this.
Any ideas how to combine Svelte-Flow with Svelte 5 with async database retrievals?
Full minimum example
// main file
<script>
import { SvelteFlow } from '@xyflow/svelte';
import '@xyflow/svelte/dist/style.css';
import { db } from '$lib/database/dexdb.js'; // Assuming you have a Dexie database setup in this file
let nodes = $state.raw([]);
let edges = $state.raw([]);
// Does not work
async function addNodeAsync() {
// Let's make it simple and use dexie.js for interacting with indexedDB -> nodes is a store in a dexie-Database
const new_id = await db.nodes.add({ type: 'input', position: { x: 100, y: 100 } });
console.log('New node added with ID:', new_id);
const some_new_node_with_id = { id: new_id, type: 'input', position: { x: 100, y: 100 } };
nodes = [...nodes, some_new_node_with_id];
}
// Works fine (reavtive)
function addNodeSync() {
const new_id = Math.random().toString(36).substring(2, 9);
const some_new_node_with_id = { id: new_id, type: 'input', position: { x: 100, y: 100 } };
nodes = [...nodes, some_new_node_with_id];
}
</script>
<button onclick={addNodeAsync}>New Node Async</button>
<button onclick={addNodeSync}>New Node Sync</button>
<div style:width="100vw" style:height="100vh">
<SvelteFlow bind:nodes bind:edges fitView></SvelteFlow>
</div>
// Dexie-DB (IndexedDB)
import Dexie from 'dexie';
export const db = new Dexie('ermStore');
db.version(1).stores({
nodes: '++id'
});
awaitin event handlers should be no issue on its own. It only really matters if the function is called in an effect (or the template, which runs in an effect), where dependencies will no longer be tracked correctly. Changes to state should still cause updates where the state is being used.