S
SolidJS6mo ago
halu

SOLVED: Non-Reactive Memo for Reactive Values?

I wish to perform a memoized calculation on demand rather than optimistically. Here we see createMemo running optimistically: https://playground.solidjs.com/anonymous/63165594-60fe-4ff2-966f-620574dd5761 Here i've solved the problem by manually tracking the dirty state and determining whether to recalc or just return at call time: https://playground.solidjs.com/anonymous/21a6530b-632c-46df-80d6-48ddd75ba665 I'm fine with this solution, but i just wanted to check that i'm not missing anything obvious
Solid Playground
Quickly discover what the solid compiler will generate from your JSX template
Solid Playground
Quickly discover what the solid compiler will generate from your JSX template
6 Replies
halu
haluOP6mo ago
for better visibility, heres the function i created:
function memo<T>(watch: () => any, cb: () => T) {
let last_val: T;

let is_dirty = true;
createComputed(() => {
watch();
console.log("made dirty");
is_dirty = true;
});

return () => {
if (is_dirty) {
last_val = cb();
is_dirty = false;
}
return last_val;
};
}
function memo<T>(watch: () => any, cb: () => T) {
let last_val: T;

let is_dirty = true;
createComputed(() => {
watch();
console.log("made dirty");
is_dirty = true;
});

return () => {
if (is_dirty) {
last_val = cb();
is_dirty = false;
}
return last_val;
};
}
mdynnl
mdynnl6mo ago
i think you’re looking for on.
const [track, trigger] = createSignal(void 0, { equals: false })
const value = createMemo(on(track, compute))

// …
trigger()
const [track, trigger] = createSignal(void 0, { equals: false })
const value = createMemo(on(track, compute))

// …
trigger()
bigmistqke
bigmistqke6mo ago
Solid Primitives
A library of high-quality primitives that extend SolidJS reactivity
halu
haluOP6mo ago
oh cool! didn’t realize there was a deferred option in on() i’ll check these out after i wake up thx guys i misunderstood defer, doesn't really help here... found that lazyMemo doesn't really work with untrack https://playground.solidjs.com/anonymous/a7e1c35c-7687-44f7-bfa3-8530bed6a914 however, untrack is no longer be necessary given how it works (at least for my use-case) https://playground.solidjs.com/anonymous/89072d00-f796-441b-ac99-4415d22f095e https://playground.solidjs.com/anonymous/6851a2d5-d67f-42a3-894a-693c95838b1d couldn't get a track/trigger version to work as trigger is always dirty, thus the memo always computes regardless of whether signals in it callback are clean/unchanged:
function memo<T>(watch: ()=>any, cb: () => any) {
const [track, trigger] = createSignal(void 0, { equals: false })
const value = createMemo(on(track, cb, {defer:true}))
return () => {
trigger()
return value();
};
}
function memo<T>(watch: ()=>any, cb: () => any) {
const [track, trigger] = createSignal(void 0, { equals: false })
const value = createMemo(on(track, cb, {defer:true}))
return () => {
trigger()
return value();
};
}
thx for the help guys!
mdynnl
mdynnl6mo ago
if i understood correctly here, you want to re-compute based on a set of dependencies and only when there are subscriptions? a combination of lazyMemo + on
halu
haluOP6mo ago
just lazyMemo was what i needed, using on/watch pattern just made it easier roll my own quickly (don't have to worry about first run tracking etc.) turns out lazyMemo primitive wasn't working in my production use-case... This is what i had to do to eliminate the watcher/on() pattern: https://playground.solidjs.com/anonymous/8dc85006-f489-46b1-887a-18d1f9c7812f
function memo<T>(cb: () => any) {
/*
The goal of this memo is to minimize recalculations,
yet still supply a syncronized value on demand.
- The only way to minimize recalculation on demand in this scenario
is to track whether dependancies go dirty (recalc required).
- Avoiding recalc on reactive updates means the
subscriptions will be cleared and the effect disposed.
This actually eliminates unnecesary side-effects entirely,
but requires the effect be re-initialized each recalculation.
*/
let [last_val, set_last] = createSignal<T>();
let is_dirty = true;

let owner = getOwner();
let effect = () => {
runWithOwner(owner, () => {
createComputed(() => {
if (is_dirty) {
console.log("recalc");
// run, memo, and mark clean
set_last(cb());
is_dirty = false;
} else {
console.log("made dirty");
// Dispose effect:
// no need to listen to subsequent updates once known to be dirty
is_dirty = true;
}
});
});
};
effect();

return () => {
// if dirty, recalc on demand
// init new comp. to listen for dirty toggle
if (is_dirty) effect();
return last_val(); // return clean memo
};
}
function memo<T>(cb: () => any) {
/*
The goal of this memo is to minimize recalculations,
yet still supply a syncronized value on demand.
- The only way to minimize recalculation on demand in this scenario
is to track whether dependancies go dirty (recalc required).
- Avoiding recalc on reactive updates means the
subscriptions will be cleared and the effect disposed.
This actually eliminates unnecesary side-effects entirely,
but requires the effect be re-initialized each recalculation.
*/
let [last_val, set_last] = createSignal<T>();
let is_dirty = true;

let owner = getOwner();
let effect = () => {
runWithOwner(owner, () => {
createComputed(() => {
if (is_dirty) {
console.log("recalc");
// run, memo, and mark clean
set_last(cb());
is_dirty = false;
} else {
console.log("made dirty");
// Dispose effect:
// no need to listen to subsequent updates once known to be dirty
is_dirty = true;
}
});
});
};
effect();

return () => {
// if dirty, recalc on demand
// init new comp. to listen for dirty toggle
if (is_dirty) effect();
return last_val(); // return clean memo
};
}
(did this mostly for fun, not sure I'd actually use it) tldr - effect runs twice to dispose itself and is recreated as necessary when recalculate on demand the neat thing is you can turn this into a lazyMemo (in the more traditional sense) by making is_dirty a signal https://playground.solidjs.com/anonymous/9180d89f-9645-41b0-be79-a4c9a649b852 https://playground.solidjs.com/anonymous/0890796b-142f-4a88-b3be-2c4521ec4552 (had to pin deps) comparison to OG lazyMemo: https://playground.solidjs.com/anonymous/f3e5d31e-56a0-463c-8754-914c6c3515c4 https://playground.solidjs.com/anonymous/16c504f7-3ffa-4532-b071-176bee23d9b9 ( had to pin deps )
Want results from more Discord servers?
Add your server