使用商店在 Svelte 中使类实例具有反应性

Eri*_*ell 5 javascript oop svelte svelte-store svelte-3

我正在通过创建简单的应用程序来学习 Svelte。

逻辑是使用类编写的。这个想法是,所有需要的数据都来自类实例属性。实例的实例化不应超过一次。我正在使用商店来提供这个实例的组件。

问题是我无法使用这种方法获得反应性。我尝试了可读和可写的商店,但没有任何帮助。仍然可以使用 OOP 获得反应性,我该怎么办?重新分配和创建新实例将是昂贵的。

编辑

我无法在 REPL 中编写示例,因为类太大了。

解析器.js

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

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

  get history() {
    return this._history;
  }
}
Run Code Online (Sandbox Code Playgroud)

在这里,我将实例传递给商店。

解析器商店.js

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

export const parserStore = writable(new Parser());
Run Code Online (Sandbox Code Playgroud)

在这个组件中,我获取了实例并被动地使用了一个方法。

Component_1.svelte *

import { parserStore } from "parserStore.js";

$: result = parserStore.parse(binded_input_value);
Run Code Online (Sandbox Code Playgroud)

我想得到的是使用类方法更新的最新时间历史属性:

Component_2.svelte

import { parserStore } from "parserStore.js";

$: history = parserStore.history;

{#each history as ... }
Run Code Online (Sandbox Code Playgroud)

我知道,这不是最好的例子,但我想要的是可通过商店获得的反应式类实例。实际上这些值是最新的,但它不会导致组件的重新渲染。当组件被安装 - 最新的数据,但在没有重新渲染之后,即使实例的属性发生了变化。

Ste*_*aes 5

简答

据我所知,你不能这样做,这样。

更长的答案

根据某些因素(如偏好、现有库等),可能有解决方法。

方案一:在类中使用stores

第一个也是最直接的一个是在类本身中使用商店:

解析器.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;
  }
}
Run Code Online (Sandbox Code Playgroud)

解析器商店.js

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

export const parser = new Parser()
Run Code Online (Sandbox Code Playgroud)

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}
Run Code Online (Sandbox Code Playgroud)

请注意如何只有history这个类的一部分是一个商店。

解决方案 2:使用自定义存储重写

这种方法本质上与前一种方法非常接近,但在 Svelte 社区中稍微更常见。从技术上讲,它只是将构建包装在商店中以获得一些额外的功能。

解析器商店.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
    }
})()
Run Code Online (Sandbox Code Playgroud)

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}
Run Code Online (Sandbox Code Playgroud)

请注意,这里history不再有属性,您直接迭代parser,如果您仍然想要历史属性,则必须稍微调整代码:

解析器商店.js

  ...
  return {
    parse,
    history: { subscribe }
  }
Run Code Online (Sandbox Code Playgroud)

Component1.svelte

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

{#each $history as h}<p>{h}</p>{/each}
Run Code Online (Sandbox Code Playgroud)


小智 5

遇到了同样的问题,并找到了如何在 svelte 中使用“反应式”类的解决方案。

在 svelte 中,任何具有订阅功能的东西都是商店。因此,如果您想为商店创建一个类,您必须实现订阅功能。

import { writable } from 'svelte/store';

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

  parse(string) {
    this._history.update(v => [...v, string])
  }
    
  subscribe(run) {
    return this._history.subscribe(run);
  }
}

export const classStore = new ClassStore();
Run Code Online (Sandbox Code Playgroud)

这是一个工作示例:https://svelte.dev/repl/8e3f4f664cc14710afce0c9683e04652 ?version=3.42.6