使用商店在 Svelte 中使 class 个实例具有反应性
Making class instance reactive in Svelte using stores
我正在通过创建简单的应用程序来学习 Svelte。
逻辑是使用classes编写的。这个想法是,所有需要的数据都来自 class 实例属性。实例不应被实例化多次。我正在使用商店来提供这种情况下的组件。
问题是我无法使用这种方法获得反应性。我尝试了可读和可写的商店,但没有任何帮助。仍然可以使用 OOP 获得反应性,我该怎么办?重新分配和创建新实例的成本很高。
编辑
我无法在 REPL 中编写示例,因为 class 太大了。
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);
我想要得到的是使用 class 方法更新的最新历史记录 属性:
Component_2.svelte
import { parserStore } from "parserStore.js";
$: history = parserStore.history;
{#each history as ... }
我知道,这不是最好的例子,但我想要的是可通过商店获得的反应式 class 实例。实际上这些值是最新的,但它不会导致组件的重新渲染。挂载组件时 - 最新的数据,但即使实例的属性已更改,也不会重新呈现任何内容。
简答
据我所知你不能这样做,这样。
更长的答案
根据某些因素(如偏好、现有库等),可能会有解决方法。
解决方案 1:使用 class
中的商店
第一个也是最直接的方法是在 class 本身中使用商店:
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}
请注意 class 中只有 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}
还有另一种方法可以将可写对象添加到 class 本身。添加一个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()
...
重点是在任何给定时刻保存 class 的状态...
遇到了同样的问题并找到了如何在 svelte 中使用“反应式”classes 的解决方案。
在苗条的情况下,任何具有订阅功能的东西都是商店。因此,如果您想 class 到商店,则必须实现订阅功能。
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
自己注意:
这似乎是一个更复杂的例子, class AND custom store(!):
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 Using stores with classes
https://livebook.manning.com/book/svelte-and-sapper-in-action/chapter-6/v-5/106
来自曼宁关于 Svelte 的书。
link中的代码部分是可见的,您只需创建一个新帐户即可免费获得整章(如果出现弹出窗口)。
潜水员:
https://devlinduldulao.pro/svelte-in-a-nutshell-with-store-code-sample/
https://medium.com/geekculture/svelte-stores-352c61759a88
我正在通过创建简单的应用程序来学习 Svelte。
逻辑是使用classes编写的。这个想法是,所有需要的数据都来自 class 实例属性。实例不应被实例化多次。我正在使用商店来提供这种情况下的组件。
问题是我无法使用这种方法获得反应性。我尝试了可读和可写的商店,但没有任何帮助。仍然可以使用 OOP 获得反应性,我该怎么办?重新分配和创建新实例的成本很高。
编辑
我无法在 REPL 中编写示例,因为 class 太大了。
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);
我想要得到的是使用 class 方法更新的最新历史记录 属性:
Component_2.svelte
import { parserStore } from "parserStore.js";
$: history = parserStore.history;
{#each history as ... }
我知道,这不是最好的例子,但我想要的是可通过商店获得的反应式 class 实例。实际上这些值是最新的,但它不会导致组件的重新渲染。挂载组件时 - 最新的数据,但即使实例的属性已更改,也不会重新呈现任何内容。
简答
据我所知你不能这样做,这样。
更长的答案
根据某些因素(如偏好、现有库等),可能会有解决方法。
解决方案 1:使用 class
中的商店第一个也是最直接的方法是在 class 本身中使用商店:
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}
请注意 class 中只有 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}
还有另一种方法可以将可写对象添加到 class 本身。添加一个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()
...
重点是在任何给定时刻保存 class 的状态...
遇到了同样的问题并找到了如何在 svelte 中使用“反应式”classes 的解决方案。
在苗条的情况下,任何具有订阅功能的东西都是商店。因此,如果您想 class 到商店,则必须实现订阅功能。
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
自己注意:
这似乎是一个更复杂的例子, class AND custom store(!):
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 Using stores with classes
https://livebook.manning.com/book/svelte-and-sapper-in-action/chapter-6/v-5/106
来自曼宁关于 Svelte 的书。
link中的代码部分是可见的,您只需创建一个新帐户即可免费获得整章(如果出现弹出窗口)。
潜水员:
https://devlinduldulao.pro/svelte-in-a-nutshell-with-store-code-sample/
https://medium.com/geekculture/svelte-stores-352c61759a88