Как лучше всего реализовать модель данных с общим доступом в представлениях Svelte

У меня есть созданное мной представление, которое содержит форму, элементы управления этой формы привязаны к свойствам объекта модели, который также используется другими представлениями). Я пытаюсь понять, действительно ли использование парадигмы Store необходимо или рекомендуется.

Например, модель будет выглядеть примерно так:

model = { 
   foo: undefined,
   bar: undefined,
   baz: undefined
}

... и пользовательский интерфейс будет иметь различные входы, привязанные к модели, примерно так:

//example.svelte
<script>
   import { exampleModel } from "./models.js";
</script>

<h2>Has foo?</h2>
<label for="input_foo_t">yes</label>
<input id="input_foo_t" type="radio" bind:group={exampleModel.foo} value={true}/>

<label for="input_foo_f">no</label>
<input id="input_foo_f" type="radio" bind:group={exampleModel.foo} value={false}/>

<h2>Has bar?</h2>
<label for="input_bar_t">yes</label>
<input id="input_bar_t" type="radio" bind:group={exampleModel.bar} value={true}/>

<label for="input_bar_f">no</label>
<input id="input_bar_f" type="radio" bind:group={exampleModel.bar} value={false}/>

В идеале хотелось бы сохранить тезисы как единое целое. Из всех примеров я вижу, что ничего подобного нет. Является ли намерение Svelte Stores предоставлять супер-детализированные данные для совместного использования, чтобы мы в основном "хранили" одно значение? Или есть примеры, которые показывают что-то вроде объекта модели, используемого в парадигме магазина? Мне не хватает какого-то процесса жизненного цикла, который мне нужно использовать с помощью Svelte Store (что-то вроде дайджеста Angular)?

2 ответа

Решение

Вы, безусловно, можете использовать для этого магазин:

// models.js
import { writable } from 'svelte/store';

export const exampleModel = writable({
  foo: undefined,
  bar: undefined,
  baz: undefined,
});
//example.svelte
<script>
   import { exampleModel } from "./models.js";
</script>

<h2>Has foo?</h2>
<label for="input_foo_t">yes</label>
<input id="input_foo_t" type="radio" bind:group={$exampleModel.foo} value={true}/>
<!-- etc -->

Сказав это, лучше не иметь огромных моделей, потому что изменение одного свойства приведет к проверке всех его зависимостей (т.е. если вы измените$exampleModel.foo, ссылки на $exampleModel.bar также будет обновляться, потому что для Svelte $exampleModelэто то, что изменилось). Обычно это не реальная проблема, но об этом нужно знать. Альтернатива, позволяющая избежать этого, - иметь более детальные значения:

// models.js
export const foo = writable();
export const bar = writable();
export const baz = writable();

Я создал два примера, которые демонстрируют, о чем говорит Рич.

  1. Первый использует одну модель (с глубиной), содержащую все три переменные (демонстрация здесь: Svelte Store Granularity (Ver 1 Single Model)).

    Установите флажок, чтобы изменить отдельную переменную. Подсчитанные изменения состояния (справа) показывают, что все три переменные ошибочно считаются измененными рефлексивно:-(

    <script>
      const fooChangeCount = createReflectiveCounter();
      const barChangeCount = createReflectiveCounter();
      const bazChangeCount = createReflectiveCounter();
    
      // monitor store-based state changes
      $: fooChangeCount.monitor($model.foo);
      $: barChangeCount.monitor($model.bar);
      $: bazChangeCount.monitor($model.baz);
    
      const reset = () => {
        fooChangeCount.reset();
        barChangeCount.reset();
        bazChangeCount.reset();
      };
    </script>
    
    <h2>Svelte Store Granularity</h2>
    <h4><i>(Ver 1 Single Model)</i></h4>
    
    <label><input type=checkbox bind:checked={$model.foo}> foo: (state changed {$fooChangeCount} times)</label>
    <label><input type=checkbox bind:checked={$model.bar}> bar: (state changed {$barChangeCount} times)</label>
    <label><input type=checkbox bind:checked={$model.baz}> baz: (state changed {$bazChangeCount} times)</label>
    
    <p><i>click to change each var: <b>state changes tallied to right</b></i></p>
    <button on:click={reset}>Reset Counts</button>
    
    <script context="module">
      import {writable} from 'svelte/store';
    
      const model = writable({
        foo: undefined,
        bar: undefined,
        baz: undefined,
      });
    
      function createReflectiveCounter() {
        // our base writable store
        // ... -1 accounts for our initial monitor reflection (bumping it to 0)
        const {subscribe, set, update} = writable(-1);
    
        // expose our newly created custom store
        return {
          subscribe,
          monitor() {
            update((count) => count + 1); // increment our count
            return '';                    // see JavaDoc
          },
          reset: () => set(0)
        };
      }
    </script>
    
  2. Второй использует несколько моделей, по одной для каждой из трех переменных (демонстрация здесь: Svelte Store Granularity (Ver 2 Multiple Models)).

    В этом случае подсчитанные изменения состояния (справа) теперь правильно показывают, что только фактически измененная переменная считается рефлексивной:-)

    <script>
      const fooChangeCount = createReflectiveCounter();
      const barChangeCount = createReflectiveCounter();
      const bazChangeCount = createReflectiveCounter();
    
      // monitor store-based state changes
      $: fooChangeCount.monitor($foo);
      $: barChangeCount.monitor($bar);
      $: bazChangeCount.monitor($baz);
    
      const reset = () => {
        fooChangeCount.reset();
        barChangeCount.reset();
        bazChangeCount.reset();
      };
    </script>
    
    
    <h2>Svelte Store Granularity</h2>
    <h4><i>(Ver 2 Multiple Models)</i></h4>
    
    <label><input type=checkbox bind:checked={$foo}> foo: (state changed {$fooChangeCount} times)</label>
    <label><input type=checkbox bind:checked={$bar}> bar: (state changed {$barChangeCount} times)</label>
    <label><input type=checkbox bind:checked={$baz}> baz: (state changed {$bazChangeCount} times)</label>
    
    <!-- Diagnostic: monitor store-based state changes -->
    <p><i>click to change each var: <b>state changes tallied to right</b></i></p>
    <button on:click={reset}>Reset Counts</button>
    
    
    <script context="module">
      import {writable} from 'svelte/store';
    
      const foo = writable();
      const bar = writable();
      const baz = writable();
    
      function createReflectiveCounter() {
        // our base writable store
        // ... -1 accounts for our initial monitor reflection (bumping it to 0)
        const {subscribe, set, update} = writable(-1);
    
        // expose our newly created custom store
        return {
          subscribe,
          monitor() {
            update((count) => count + 1); // increment our count
            return '';                    // see JavaDoc
          },
          reset: () => set(0)
        };
      }
    </script>
    

Надеюсь это поможет!

</Kevin>

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