YousefED/SyncedStore

References kept to objects within the synced store become empty on their own

douira opened this issue · 7 comments

An error occurs in the following reproduction sandbox (adapted from the one in the documentation for syncedstore and vue). There are two input fields, the first one uses the reactive object contained within the store for getting the model property. The second one uses the full reference path to the store. The first input field errors when it's touched by the user (the value changed) since the object becomes empty because SyncedStore modifies it in a weird way.

https://codesandbox.io/s/sandpack-project-forked-p3fkw6?file=/src/App.vue

<template>
  <main id="app">
    baz.title.foo.content
    <input
      autocomplete="off"
      v-model="baz.title.foo.content"
    />
    store.documents.baz.title.foo.content
    <input
      autocomplete="off"
      v-model="store.documents.baz.title.foo.content"
    />
  </main>
</template>

<script>
import { store } from "./store";
import { ref } from "vue";
import * as Vue from "vue";
import { enableVueBindings } from "@syncedstore/core";

// make SyncedStore use Vuejs internally
enableVueBindings(Vue);

export default {
  name: "App",
  setup() {
    store.documents.baz = {
      completed: false,
      title: {
        foo: {
          content: "foo",
          user: null
        }
      }
    };
    const baz = store.documents.baz;
    return {
      store, // Put the store on the data() of the component
      baz
    };
  }
};
</script>

...
import { syncedStore, getYjsValue } from "@syncedstore/core";
import { WebrtcProvider } from "y-webrtc";

type Todo = {
  completed: boolean
  title: {
    foo: {
      content: string,
      user: null
    }
  }
}

export const store = syncedStore({
  documents: {} as Record<string, Todo>
})

...

I tried reproducing it, but it worked fine in this sandbox:

https://codesandbox.io/s/sandpack-project-forked-tr1bjc?file=/src/store.ts

I've passed a clean roomname "vue-issue-debug" to WebrtcProvider, perhaps the data was syncing with another project that corrupted the store?

I tried reproducing it, but it worked fine in this sandbox:

https://codesandbox.io/s/sandpack-project-forked-tr1bjc?file=/src/store.ts

I've passed a clean roomname "vue-issue-debug" to WebrtcProvider, perhaps the data was syncing with another project that corrupted the store?

It appears that syncing is causing the problem for me. I've used a random clean roomname and the issue is happening. It only happens if there are actually two browser tabs open with the same roomname so that syncing does happen. Then entering any character into the input field results in Cannot read properties of undefined (reading 'foo'). If you'd like I can record a video of the exact reproduction steps.

Got it. The issue here is that you store a local value using const baz = store.documents.baz;

However, when syncing across clients, store.documents can be overwritten by a sync. This means baz is no longer valid. You should therefor reference your object from store directly

I'll have to work with functions that access the properties or computed getters or sth then. Thanks for the clarification!

Maybe a hint about this behavior could be added to the documentation? It's not immediately obvious that the library behaves in this way since by default, reactive references in Vue don't suddenly become invalidated.

I think this would go wrong in native Vue as well to be honest. It might not give an error, but if you'd overwrite store.documents.baz from somewhere else, then the dereferenced "baz" should be outdated

You're right, that would break it too.