【问题标题】:Making class instance reactive in Svelte using stores使用商店在 Svelte 中使类实例具有反应性
【发布时间】:2020-07-13 21:06:39
【问题描述】:

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

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

问题是我无法使用这种方法获得反应。我尝试了可读可写存储,但没有任何帮助。仍然可以使用 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 ... }

我知道,这不是最好的例子,但我想要的是通过商店提供的反应类实例。实际上这些值是最新的,但它不会导致组件的重新渲染。安装组件时 - 最新数据,但即使实例的属性发生更改,也不会重新渲染。

【问题讨论】:

  • 我们需要看看你做了什么。在此处或在纤细的 REPL 上显示您的代码。
  • @AndreasDolk 我试图提供一些例子,希望对您有所帮助!

标签: javascript oop svelte svelte-3 svelte-store


【解决方案1】:

简答

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

更长的答案

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

解决方案 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:使用自定义商店重写

这种方法本质上与前一种方法非常接近,但在 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}

【讨论】:

【解决方案2】:

还有另一种方法可以向类本身添加可写对象。添加save()方法:

Parser.js

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

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

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

Component_1.svelte

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

// create new class instance
const p = new Parser();

// add some values
p.parse(binded_input_value);

// save that class instance
const parserStore = writable(p.save());

// can be called after page is loaded
function showHistory() {
  console.log(get(parserStore).history);
}

页面加载后可以保留该值,可以将p.save()传递给子组件,或者如果组件2不是子组件,则可以使用setContext()getContext()...

关键是在任何给定时刻保存类的状态...

【讨论】:

    【解决方案3】:

    遇到了同样的问题,并找到了如何在 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();
    

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

    【讨论】:

      【解决方案4】:

      给自己的注意:
      这里似乎是一个更复杂的例子,带有类 AND 自定义存储(!):

      https://gist.github.com/3lpsy/55da83779a50f603a78ae8331e360a37

      有趣:

      /*
      I recently jumped into svelte programming and wanted to create a class/singleton that could double as a reactive writable store. 
      I did things very wrong until people on the discord confirmed how wrong my implementation was so I wanted to provide a simple example.
      So below is a simple account store you can use. I'm not sure if it's optimal or even correct, but it's better than my first attempt. 
      Feel free to provide feedback.
      */
      ...
      

      编辑,
      还有这个:

      6.7 将商店与类一起使用

      https://livebook.manning.com/book/svelte-and-sapper-in-action/chapter-6/v-5/106
      来自曼宁关于 Svelte 的书。
      链接中的代码部分是可见的,您只需创建一个新帐户即可免费获得整章(如果出现弹出窗口)。

      潜水员:
      https://devlinduldulao.pro/svelte-in-a-nutshell-with-store-code-sample/ https://medium.com/geekculture/svelte-stores-352c61759a88

      【讨论】:

        猜你喜欢
        • 2022-06-14
        • 2018-07-20
        • 2021-10-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-02-27
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多