Подпишитесь на документ с помощью Svelte / RxJs / RxFire. Как мне обновить подписку

Я использую производное хранилище в приведенном ниже коде. Это выглядит странной конструкцией, потому что я использую производную конструкцию только для динамической зависимости $session и для получения normData. Но не с нормой $. Я использую $norm только один раз, чтобы запустить производное хранилище.

Тем не менее, похоже, все работает нормально. Но я должен продлить подписку, если $session изменится. Можно ли обновить подписку RxFire / RxJs без предварительного отказа от подписки?

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();
}); 

Обновление: я могу использовать параметры set и return производного хранилища, чтобы изменить $norm в реальном хранилище $norm Svelte. Код ниже в моем собственном ответе.

Но реальный вопрос: могу ли я обновить подписку. Сменить подписку без отписки?

2 ответа

Решение

У меня уже был ответ, но я его не осознавал.

Ниже производного кода магазина с параметрами set () и return ().
Когда сеанс изменяется, return () автоматически отписывается.
Так что все еще отписываюсь от подписки, а не обновляю... но это хорошо. Приятно!

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:

Получает магазин от одного или нескольких других магазинов. Каждый раз, когда эти зависимости меняются (например, $session), выполняется обратный вызов.

Если вы "возвращаете функцию" из обратного вызова, она будет вызываться (перед обратным вызовом), когда а) обратный вызов запускается снова (из-за изменения зависимости) или б)...

Хорошо, примерно то, что вы пытаетесь описать здесь.

Фактически вы можете использовать реактивное объявление для выполнения кода при изменении переменной / хранилища.

В этом случае следует выполнить метод повторной подписки:

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();
}); 

Ключевым моментом здесь является то, что при компиляции Svelte знает, что блок зависит от $session, поэтому он будет повторно выполнять блок кода всякий раз, когда $session изменилось.

Если вы захотите преобразовать его в другую функцию, вы должны убедиться, что Svelte знает, что функция зависит от $session, то есть:

$: resubscribe_norm($session);

Здесь Svelte может сказать, что если $session поменял, нужно позвонить resubscribe_norm еще раз.

Другие вопросы по тегам