Делаем экземпляр класса реактивным в Svelte с помощью хранилищ - PullRequest
1 голос
/ 14 июля 2020

Я изучаю Svelte, создавая простое приложение.

Лог c написан с использованием классов. Идея состоит в том, что все необходимые данные поступают из свойств экземпляра класса. Экземпляры не следует создавать более одного раза. Я использую магазины для предоставления компонентов этим экземплярам.

Проблема в том, что я не могу получить реактивность, используя этот подход. Я пробовал магазины с возможностью чтения и записи, и ничего не помогло. Еще можно получить реактивность, используя OOP, и что мне делать? Переназначение и создание новых экземпляров будет дорогостоящим.

Изменить

Я не могу составить пример в REPL, потому что класс слишком велик.

Parser. js

export default class Parser {
  constructor() {
    this._history = [];
  }

  parse(string) {
    this._history.push(string)
  }

  get history() {
    return this._history;
  }
}

Здесь я передаю экземпляр в магазин.

parserStore. js

import writable from "svelte/store";
import Parser from "Parser.js"

export const parserStore = writable(new Parser());

В этом компоненте я получаю экземпляр и реактивно использую метод.

Component_1.svelte *

import { parserStore } from "parserStore.js";

$: result = parserStore.parse(binded_input_value);

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

Component_2.svelte

import { parserStore } from "parserStore.js";

$: history = parserStore.history;

{#each history as ... }

Я знаю, это не лучший пример, но я want - это реактивный экземпляр класса, доступный в магазине. На самом деле значения актуальны, но это не вызывает повторной визуализации компонентов. Когда компонент смонтирован - данные самые свежие, но после того, как ничего не перерисовывается, даже если свойства экземпляра изменены.

1 Ответ

2 голосов
/ 14 июля 2020

Короткий ответ

Насколько я знаю, вы не можете сделать это таким способом.

Более длинный ответ

В зависимости от некоторых факторов (например, предпочтений, существующих библиотек и т. Д. c ...) могут быть способы обойти это.

Решение 1. Используйте магазины в классе

Первый и самый простой - использовать хранилища в самом классе:

Parser. js

import { writable } from 'svelte/store'

class Parser {
  constructor() {
    this._history = writable([])
  }

  parse(string) {
        console.log(string)
    this._history.update(v => [...v, string])
  }

  get history() {
    return this._history;
  }
}

parserStore. js

import { Parser } from './Parser.js'¨

export const parser = new Parser()

Component1.svelte

<script>
    import { parser } from './parserStore.js';

    let value
    let { history } = parser
    
    $: parser.parse(value);
</script>

<input bind:value />

{#each $history as h}<p>{h}</p>{/each}

Обратите внимание, что только часть history этого класса будет хранилищем.

Решение 2. Перепишите, используя Custom Store

Этот подход, по сути, очень близок к предыдущему, но немного более распространен в сообществе Svelte. Технически он просто обертывает сборку в магазинах, чтобы получить дополнительную функциональность.

parserStore. js

import { writable } from 'svelte/store'

export const parser = (() => {
    const P = writable([])  
    const { set, subscribe, update } = P    
    
    function parse(string) {
        P.update(arr => [...arr, string])
    }
    
    return {
        parse,
        subscribe
    }
})()

Component1.svelte

<script>
    import { parser } from './parserStore.js';

    let value
    $: parser.parse(value)
</script>

<input bind:value />

{#each $parser as h}<p>{h}</p>{/each}

Обратите внимание, что здесь больше нет свойства history, вы повторяете прямо parser, если вам все еще нужно свойство истории, вам нужно немного изменить код:

parserStore. js

  ...
  return {
    parse,
    history: { subscribe }
  }

Component1.svelte

<script>
  ...
  const { history } = parser
  ...
</script>

{#each $history as h}<p>{h}</p>{/each}
...