I'm trying to implement what seems to be quite a common pattern but can't write it easily.
In a nutshell, I need a derived store derived from both an array and its items
Let me provide some context because I really feel I'm missing a concept but can't find anything on Stack Overflow, GitHub issues (this one is interestingly related but unresolved yet) or the broader internet (this article provides a solution that doesn't seem to work, unfortunately).
Pattern I'm trying to implement
What I'm trying to achieve really well fits the example of an invoice:
- an invoice has multiple invoice items
- each invoice item has a unit price
- each invoice item has a quantity
- each invoice item has a subtotal (unit price × quantity)
- the invoice has a dynamically computed total price
I need the invoice total price to be reactive and to depend on both:
- the number of invoice items (I want the total price to update automatically when I add an item)
- each invoice item subtotal (I want the total price to update automatically when I change an item quantity)
Implementation
️ Here is the full implementation in Svelte REPL: https://svelte.dev/repl/164f13f5d99b46e7a8f4cb9627db2aee?version=3.44.1
The data model:
- an
InvoiceItemhas:- a static
name - a static
unitPrice - a writable store
quantity(which defaults to1)
- a static
- an
Invoicehas:- a writable store
items(which defaults to[]and will contain manyInvoiceItems)
- a writable store
Reactive attributes / computations:
- an
InvoiceItemhas:- a
subTotalattribute which is a derived store (derived from itsquantityattribute)
- a
- an
Invoicehas:- a
totalattribute which is a derived store (derived from itsitemsattribute) which returns another derived store (derived from all theInvoiceItems)
- a
I call this derived store which returns another derived store a "metastore" (please feel free to suggest a better name ).
Problem
Consuming the metastore requires to first (auto-)subscribe to the higher-level store (total), then to (auto-)subscribe to the derived store returned by the first subscription.
It results in something like this:
$: invoiceTotalMetaStore = invoice.total
$: invoiceTotal = $invoiceTotalMetaStore
Which is cumbersome / unnecessarily verbose.
Also, this is a simple data model with a 1-level metastore, but what if another use-case would require more deeply nested data? (a derived store that returns another derived store that returns still another derived store )
Is there something obvious I'm missing to implement this pattern? What would the community recommend?