1

I use a derived store in the code below. It feels like a strange construct because I only use the derived construct for the dynamic $session dependency and to get the normData. But not with $norm. I use $norm only once to kick off the derived store.

Nevertheless it seem to work fine. But I have to renew the subscription if the $session changes. Is it possible to update the RxFire / RxJs subscription without unsubscribing first?

let normDocRef = null;
let normData = null;
let normSubscription = null;

const norm = derived(
  session,
  $session => {
    normDocRef = db.doc(`uploads/${$session.a_id}_${$session.year}`);

    // renew the subscription if $session changes   
    if (normSubscription) 
      normSubscription.unsubscribe();

    normSubscription = doc(normDocRef).subscribe(snapshot => {
      if (snapshot.exists) {
        normData = snapshot.data();
      } else {
        normData = null;
      };
    });
  },
);

$norm;   // kick off the derived store to monitor $session

// show the data and updates
$: console.log(normData); 

onDestroy(() => {
  if (normSubscription) normSubscription.unsubscribe();
}); 

Update: I can use the set and return options of the derived store to change $norm in a real $norm Svelte store. Code below in my own answer.

But the real question is: Can I update a subscription. Change the subscription without the unsubscribe?

voscausa
  • 11,253
  • 2
  • 39
  • 67
  • Correct me if I misunderstood your question, you want to resubscribe to `normDocRef` whenever the `session` changes? – Tan Li Hau Nov 12 '19 at 06:40
  • The name of the doc contains a year like, Foo2010..Foo2019. So when I change the session year I want to update the subscription. – voscausa Nov 12 '19 at 07:16

2 Answers2

1

I already had the answer, but did not realize it.

Below the derived store code with the set() and return() options.
When the session changes the return() will unsubscribe automatically.
So still an unsubscribe and not an update ... but this feels good. Nice!

let normDocRef = null;
let normSubscription = null

const norm = derived(
  session,
  ($session, set) => {
    normDocRef = db.doc(`uploads/${$session.a_id}_${$session.year}`);
    normSubscription = doc(normDocRef).subscribe(snapshot => {
      if (snapshot.exists) {
        set(snapshot.data());
      } else {
        set({}); // clear
      };
    });
    return () => {  
      normSubscription.unsubscribe();
    };
  }, {}  // initial value
);

$: console.log('$norm', $norm);  // Now it is a real store

onDestroy(() => {
  if (!normSubscription.closed) {
    normSubscription.unsubscribe();
  }
});

API docs derived store:

Derives a store from one or more other stores. Whenever those dependencies change (like the $session), the callback runs.

If you "return a function" from the callback, it will be called (before the callback) when a) the callback runs again (because the dependency changed), or b) ...

voscausa
  • 11,253
  • 2
  • 39
  • 67
0

Ok, roughly get what you trying to describe over here.

You can actually use the reactive declaration to execute code when a variable / store changed.

In this case is to execute the resubscribe method:

let normDocRef = null;
let normData = null;
let normSubscription = null;

$: {
  normDocRef = db.doc(`uploads/${$session.a_id}_${$session.year}`);
  // renew the subscription if $session changes   
  if (normSubscription) {
    normSubscription.unsubscribe();

    normSubscription = doc(normDocRef).subscribe(snapshot => {
      if (snapshot.exists) {
        normData = snapshot.data();
      } else {
        normData = null;
      };
    });
  }
}

onDestroy(() => {
  if (normSubscription) normSubscription.unsubscribe();
}); 

The key here, is that when compiling this, Svelte knows that the block is depending on $session, so it will re-execute the code block whenever $session changed.

Should you want to refactor it out into another function, you need to make sure that Svelte knows that function depends on $session, ie:

$: resubscribe_norm($session);

Here, Svelte can tell that, if $session changed, need to call resubscribe_norm again.

Tan Li Hau
  • 1,984
  • 17
  • 24
  • This is not the problem. The derived store depends on the session and will renew the subscription whenever the session changes. It works fine in the code I showed. No problems here. But is it possible to update the subscription (query). Switch to another doc without unsubscribe / subscribe. – voscausa Nov 12 '19 at 07:51
  • Thanks for your response. I have also updated the question. It was not clear. – voscausa Nov 12 '19 at 08:38
  • not sure what you are looking for, whether you can update a subscription without the unsubscribe, it's depend on the `db.doc`, which is not from svelte right? – Tan Li Hau Nov 12 '19 at 13:29
  • maybe you can reactively declare `$: normDocRef = db.doc(\`uploads/${$session.a_id}_${$session.year}\`)`, then derive `norm` instead of `$session`. so you can also change `normDocRef` manually if you want. – Tan Li Hau Nov 12 '19 at 13:30