Svelte store условная автоподписка - PullRequest
0 голосов
/ 16 апреля 2020

Шаги воспроизведения:

Ожидается :

Я думал, что $store может подписаться (с $:) только , если canSubscribe истинно.

Вопрос: Почему $store подписывается, если canSubscribe ложно?

Я не прав?

Ответы [ 3 ]

2 голосов
/ 17 апреля 2020

Svelte обходит AST в время компиляции , чтобы определить автоматическую подписку.

Он устанавливает подписку, даже когда код, обращающийся к магазину, недоступен.

Например:

import {foo} from './stores'

let condition = false

if (condition) { $foo }

Несмотря на то, что $foo технически недоступен, это не будет известно до времени выполнения.

Альтернатива : вы всегда можете использовать ручную подписку, чтобы обойти это. Пример:

import {onDestroy} from 'svelte'
import {myStore} from './stores.js'

// subscribe when component is created
const unsubscribe = myStore.subscribe(value => {
  // this is called anytime the value of myStore changes
})

// make sure to unsubscribe when component is unmounted
onDestroy(unsubscribe)
1 голос
/ 20 апреля 2020

Я не прав?

Да. Не вини себя, хотя, твои ожидания кажутся мне только логичными. Но это не совсем так.

Как правило, если где-то в коде компонента есть префиксная переменная $, тогда это должно быть хранилище , и оно будет подписываться сразу при создании компонента и отписываться при уничтожении компонента.

Небольшое исключение из этого правила было введено совсем недавно (с этим PR ). Я позволю вам пройти по тропе вниз по кроличьей норе, если вы хотите узнать всю дискуссию. Суть в том, что теперь подписка на магазин должна быть магазином или nulli sh (то есть null или undefined - см. этот комментарий ).

Это означает, что теперь можно при желании взломать ваш путь к ожидаемому вами поведению. Мы возвращаемся к этому.

Почему $ store подписывается, если canSubscribe имеет значение false?

Поскольку магазины подписаны сразу. Насколько я понимаю из обсуждения вышеизложенных вопросов, оно относится к производительности (размеру байта) и здравому смыслу (быстро и явно проваливается, если кто-то пытается подписаться на то, что не является магазином). Имеет смысл для меня.

Теперь вернемся к вопросу, который вы не задавали: как подписаться только когда / если необходимо? Поместите хранилище в переменную с автоподпиской только при необходимости и оставьте значение nulli sh в противном случае.

Не делайте:

$: started && $store

Сделайте это вместо:

$: proxyStore = started ? store : null
$: console.log($proxyStore)

Полный пример ( REPL ):


    import { writable } from 'svelte/store'

    const state1 = { subscribed: 0, unsubscribed: 0 }

    const store1 = writable(42, () => {
        state1.subscribed++
        return () => {
            state1.unsubscribed++
        }
    })

    const state2 = { subscribed: 0, unsubscribed: 0 }

    const store2 = writable(43, () => {
        state2.subscribed++
        return () => {
            state2.unsubscribed++
        }
    })

    let started = false

    $: started && $store1

    $: targetStore = started ? store2 : null

    $: $targetStore



started = {started}
store1 = {$store1} {JSON.stringify(state1)}
store2 = {$targetStore} {JSON.stringify(state2)}
{начато =! Началось}}> {началось? «Пуск»: «Стоп»}
1 голос
/ 16 апреля 2020

В реактивном утверждении $: canSubscribe && $store у вас есть выражение для оценки. Поскольку он реагирует, Svelte должен определить, когда нужно переоценить это выражение, и это произойдет в двух случаях: когда изменяется canSubscribe или когда $store. Таким образом, он должен будет подписаться на оба этих значения, поэтому вы видите, что вы сразу получаете подписчика в своем коде.

Обратите внимание, что мы часто делаем canDoSomething && canDoSomething() в JavaScript но это не на 100% то же самое, что if (canDoSomething) { canDoSomething()}, в большинстве случаев он имеет тот же эффект.

...