【发布时间】:2021-12-30 07:04:20
【问题描述】:
我有一个包含实体列表的商店,以及另一个包含这些实体的对象的商店。
我希望第一个商店中的更改能够反应性地反映在第二个商店中。
我将提供一个包含项目列表和发票列表的快速示例
export type Invoice = {
id: string
customer: string
items: InvoiceItem[]
}
export type InvoiceItem = {
id: string
name: string
price: number
}
每当更新发票项目的名称或价格时,我希望所有相关发票也更新。
我创建了这个非常简单的示例(repl available here),但为了更新 $invoices 存储,我必须在 $items 存储发生变化时发出 $invoices = $invoices。
另一种更优雅的方法是订阅项目商店并从那里更新发票商店,如下所示:
items.subscribe(_ => invoices.update(data => data))
<script>
import { writable } from 'svelte/store'
let item1 = { id: 'item-01', name: 'Item number 01', price: 100 }
let item2 = { id: 'item-02', name: 'Item number 02', price: 200 }
let item3 = { id: 'item-03', name: 'Item number 03', price: 300 }
let items = writable([item1, item2, item3])
let invoices = writable([
{ id: 'invoice-0', customer: 'customer1', items: [item1, item3] }
])
items.subscribe(_ => invoices.update(data => data)) // refresh invoices store whenever an item is changed
const updateItem1 = () => {
$items[0].price = $items[0].price + 10
// $invoices = $invoices // alternatively, manually tell invoices store that something changed every time I change and item!!!
}
</script>
<button on:click={updateItem1}>update item 1 price</button>
<hr />
<textarea rows="18">{JSON.stringify($invoices, null, 2)}</textarea>
<textarea rows="18">{JSON.stringify($items, null, 2)}</textarea>
这是处理这种情况的最佳方式吗?
更新:感谢出色的答案和 cmets,我提出了这个更完整的示例:请参阅repl
我添加了一些功能,希望可以作为类似常见场景的基础
这就是我的 store api 的结果:
// items.js
items.subscribe // read only store
items.reset()
items.upsert(item) // updates the specified item, creates a new one if it doesn't exist
// invoices.js
invoices.subscribe // read only store
invoices.add(invocieId, customer, date) // adds a new invoice
invoices.addLine(invoiceId, itemId, quantity)
invoices.getInvoice(invoice) // get a derived store for that particular invoice
invoice.subscribe // read only store
invoice.addLine(itemId, quantity)
几个亮点
- invoices 现在有一个
lines数组,每个数组都有一个项目和一个数量 - invoices 是一个派生存储,用于计算每行和整个发票的总计
- 在 items 中实现 upsert 方法
- 为了在修改项目时更新发票,我运行
items.subscribe(() => set(_invoices)) - 还创建了派生商店以获取特定发票
【问题讨论】:
-
显然赞成订阅方法,因为它更好地表达了您的意图(正如您所指出的那样,它更优雅),即“让发票商店按顺序订阅商品商店后者的变化会触发前者的更新”。话虽如此,发票和物品是一个糟糕的示例选择。在现实世界的应用程序中,项目将是不可变的(至少在给定发票的范围内)并且可能来自外部来源。只有它们的数量会发生变化,并且该数据将位于发票本身中,因此确实不需要物品商店;)
-
非常感谢您的评论,请查看更新的工作示例:svelte.dev/repl/d9fb573137cc468b8efa256701d39f6b?version=3.44.2