rxjssveltederivedrxfire

Subscribe to a doc using Svelte / RxJs / RxFire. How can I update the subscription


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?


Solution

  • 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) ...