YousefED / SyncedStore

SyncedStore CRDT is an easy-to-use library for building live, collaborative applications that sync automatically.
https://syncedstore.org
MIT License
1.69k stars 51 forks source link

Trouble with Svelte #100

Open mlaass opened 1 year ago

mlaass commented 1 year ago

I'm trying to get the svelte examples to work on my local machine So far I have removed the yjs dependency from the package because it would trigger an error/warning and added items = items in the submit function, which leads to the item list being re-rendered. It then shows, that items have been submitted before.

What is missing though, is that the when new items are added from other windows, or when the window loads, no rendering is triggered. I'm not quite sure how to go about this. But I'm guessing there is something not quite right in this function in @syncedstore/svelte:

export function svelteSyncedStore<T>(syncedObject: T) {
  let set: any;
  const observer = new Observer(() => {
    if (set) {
      set(store);
    }
  });
  const store = reactive(syncedObject, observer);

  const readableStore = readable(store, (newSet) => {
    set = newSet;

    return () => {
      set = undefined;
    };
  });

  return {
    subscribe: readableStore.subscribe,
    set: () => {}
  }
}

Any help in making this work would be appreciated. I'm happy to do a PR once I get this to work.

N-NeelPatel commented 1 year ago

@mlaass - To ensure that the rendering is triggered when new items are added or when the window loads, you can modify the svelteSyncedStore function as follows:

export function svelteSyncedStore<T>(syncedObject: T) {
  let set: any;
  const observer = new Observer(() => {
    if (set) {
      set(store);
    }
  });
  const store = reactive(syncedObject, observer);

  const readableStore = readable(store, (newSet) => {
    set = newSet;
    set(store); // Trigger initial rendering

    return () => {
      set = undefined;
    };
  });

  return {
    subscribe: readableStore.subscribe,
    set: (newValue) => {
      store = newValue; // Update the store value
      if (set) {
        set(store); // Trigger rendering
      }
    }
  }
}

In this modified version, I've made a couple of changes:

  1. I added set(store) in the readableStore callback to trigger the initial rendering when the store is subscribed to.
  2. I modified the set function to accept a newValue parameter and update the store value accordingly. After updating the store value, it triggers the rendering by calling set(store) if it exists.

With these modifications, the rendering should be triggered when new items are added from other windows or when the window loads.

mrTorb commented 1 year ago

in the example I found out that in order for it to work you have to see to that webrtc is not used on the server side, so i added this, and now it works perfectly.

store.ts

import { syncedStore, getYjsDoc } from "@syncedstore/core";
import type { WebrtcProvider } from "y-webrtc";
import { svelteSyncedStore } from "@syncedstore/svelte";

// Create your SyncedStore store
export const store = syncedStore({ todos: [] });
export const svelteStore = svelteSyncedStore(store);

let webrtcProvider:WebrtcProvider;

console.log(import.meta.env.MODE);

//prevent server side
if (typeof window !== 'undefined') {

    const { WebrtcProvider } = await import('y-webrtc');

    // Create a document that syncs automatically using Y-WebRTC
    const doc = getYjsDoc(store);
    webrtcProvider = new WebrtcProvider("syncedstore-todos", doc);

}

export const disconnect = () => webrtcProvider.disconnect();
export const connect = () => webrtcProvider.connect();
mrTorb commented 1 year ago

It should be noted that the code I'm working with was sourced from the webpage and the example provided is a bit different from the current code in the repository.