Derived stateful classes #18055
Replies: 2 comments
-
|
Your 1. Let the constructor take "reactive inputs" as functionsInstead of reading type Reactive<T> = () => T
class CounterWithAdded {
counter = $state(0)
#addFn: Reactive<number>
constructor(opts: { add: Reactive<number> }) {
this.#addFn = opts.add
this.sum = $derived(this.counter + this.#addFn())
}
sum: number
}
const a = new Counter()
const c = new CounterWithAdded({
add: () => a.counter, // no getter boilerplate, still reactive
})Arrow functions are cheap to write, the reactive graph still correctly subscribes to 2. A tiny helper for "bag of reactive inputs"If you have a lot of these, make the thunk-to-getter conversion a utility so the class stays ergonomic: function reactify<T extends Record<string, () => unknown>>(thunks: T) {
const bag = {} as { [K in keyof T]: ReturnType<T[K]> }
for (const k of Object.keys(thunks) as (keyof T)[]) {
Object.defineProperty(bag, k, { get: thunks[k], enumerable: true })
}
return bag
}
// usage
const c = new CounterWithAdded(reactify({
add: () => a.counter,
multiplier: () => someOther.value,
name: () => user.fullName,
}))Now 3. For the store-factory pattern, compose classes, not functionsYour Svelte-4 example is literally a function returning a bag of stores. In runes land the direct translation is a class returning a bag of class UserCardsStore {
cards = $state<Card[]>([])
}
class UserCreditCardsStore {
creditStatus = $state<'new' | 'active' | 'blocked'>('new')
#base: UserCardsStore
creditCards: Card[]
constructor(base: UserCardsStore) {
this.#base = base
this.creditCards = $derived(this.#base.cards.filter((c) => c.type === 'credit'))
}
}
const user = new UserCardsStore()
const credit = new UserCreditCardsStore(user)
Your Rule of thumb
That's the whole design space in the runes model. Once the team internalises "pass instances for ownership, pass thunks for loose inputs," the Svelte-4 store-composition shapes migrate without getting ugly. |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
Is there an idiomatic way to do this? basically i have state, then I have some derived state but it's not pure - it's stateful too.
here's a basic example
as for the real use case - we're a bank and we have a lot of functions built around svelte 4 stores where a function sets up a bunch of state, and then reused by other functions which derive from its state but declare its own state too and so on. when migrating this to runes - it's not very clear whats a nice, clean solution
it may look like this
assume
creditStatuscannot just be a derived and since it needscreditCards, we can't just split these stores - it kinda has to be a stateful derived. And it's a big app so we can't be changing the logic much here so of course ideally there should be a straightfoward way to move store code to rune code.I guess the 4th option is to introduce some
Runetype{ current: T}- akin to whatfromStorereturns and use that instead ofReadable/WritableeverywhereThis probably has been asked before but kinda hard to search for
This is a duplicate question from Discord: https://discord.com/channels/457912077277855764/1489264519468552294
Beta Was this translation helpful? Give feedback.
All reactions