Mass Normalization of Props

Hi all, I find myself in the situation of wanting to provide non-reactive alternatives for some component props, i.e. allowing other devs to provide any of
interface SomeProps {
foo?: Accessor<T> | T; // Accessor<T> | T | undefined
}
interface SomeProps {
foo?: Accessor<T> | T; // Accessor<T> | T | undefined
}
Currently, I've done this manually by; for any property x, of type T (literal), x = () => T. Which in code is a whole lot of if statements.
Now, I could see how this could be a generic utility function - with support for providing defaults too, so does this exist already? I'm aware of mergeProps, but that isn't exactly what I'm looking for. I'm also (now at least), aware of the babel pre-processing plugin, which seems handy enough, but I recon a function like the one described above would be pretty useful overall for allowing greater flexibility for all component props. Plugin or not.
17 Replies
Fexelitche
FexelitcheOP4w ago
For better detail, the implementation would go something like:
function normalizeProps(props) {
for (const key in props) {
if (typeof props[key] !== "function") {
const prev = props[key];
props[key] = () => prev;
}
}
}
function normalizeProps(props) {
for (const key in props) {
if (typeof props[key] !== "function") {
const prev = props[key];
props[key] = () => prev;
}
}
}
Typing it would be a decable tho Also extensions could be made to ignore keys, include others, defaults... stuff like that
Brendonovich
Brendonovich4w ago
Props are transformed into getters and proxies, if you do foo={bar()} then props.foo will be reactive, no need to have Accessor<T> as the type. Is there a particular reason you want to allow providing Accessor<T>?
Fexelitche
FexelitcheOP4w ago
But that is only with that babel-plugin is it not? (One might not have that available if one set up their project like a doofus)
mdynnl
mdynnl4w ago
@fabiospampinato would enjoy seeing this thread :fabio:
Brendonovich
Brendonovich4w ago
If you're not using the babel plugin for the jsx transform you can still define the getters yourself Though surely you're using jsx
Fexelitche
FexelitcheOP4w ago
yes yes, of course. What exactly do you mean by defining the getters yourself? Sure, Icould wrap stuff in a lambda when providing the prop, but that'd be annoying to have to do all the time.
Brendonovich
Brendonovich4w ago
Yeah you'd basically have to do that
const [state, setState] = createSignal();

Component({
get value() {
return state()
}
})
const [state, setState] = createSignal();

Component({
get value() {
return state()
}
})
Fexelitche
FexelitcheOP4w ago
Well, that's cursed. I think Ill go make that prop normalization utility
Brendonovich
Brendonovich4w ago
If you're fine with using proxies then they could probably make it easier
Fexelitche
FexelitcheOP4w ago
What do you mean by proxies?
Brendonovich
Brendonovich4w ago
js proxies, the thing stores use you could intercept prop reads and call the accessor if the prop is a function with normalizeProps you'd need to account for if the prop is a getter itself and copy it rather than just the prop value not a bad thing, just something to note
fabiospampinato
I think in general bailing out of the transform won't lead you to a pleasant path for Solid Solid is meant to be used with the transform Like the use case you have is kinda thought to be non existent in Solid, you should support reacting to any prop even though there are some weird edge cases where for performance, or for simplicity, you do just want to say that something cannot be reactive because that's unsupported by your thing Examples: - switching between 2 virtualization modes on the same component, maybe one requires refs and the other doesn't, if you want to support that now you need to pass refs all the time, which for one of the modes is wasteful - maybe you have a createDebounced or something, supporting the wait time changing is trickier than it may seem (what happens if that's updated before it has a chance to trigger? do you reset the timer so the callback is potentially never triggered?). If you never need that there's no reason to even think about it imo
Fexelitche
FexelitcheOP4w ago
That seems generally problematic. Sure, the reactivity graph is very performant, and sure, you COULD react to any prop, but that doesn't mean you should. Itd actually be problematic if you couldn't choose not to - which I've experienced many a time not realizing what exactly is tracked in createEffect and such (thank you whomever made untrack). How could you possibly hope to control your updates if everything is always reactive? I really would rather prefer it always being explicit.
fabiospampinato
do you care about SSR/hydration?
How could you possibly hope to control your updates if everything is always reactive?
~everything could possibly be reactive in Solid, where "everything" is basically either a function call or a property access, basically anything that could end up calling a function
bigmistqke
bigmistqke4w ago
yes, the assumption in solid is that all props could be reactive.
Itd actually be problematic if you couldn't choose not to
you can choose not to: that is what untrack is for a oops didn't read properly, you mentioned untrack too
bigmistqke
bigmistqke4w ago
I recommend https://www.youtube.com/watch?v=cELFZQAMdhQ to get an initial intuition for how solid's reactivity works, including those props-getters
SolidJS
YouTube
Intro to SolidJS reactivity (in 5 minutes)
An introduction video that walks you through Solid's reactivity in under 5 minutes.
bigmistqke
bigmistqke4w ago
the props-transform is a hotly debated topic. fabio has a signal ui framework called voby that doesn't do it, it will have code that looks more like your initial sample.
GitHub
GitHub - vobyjs/voby: A high-performance framework with fine-graine...
A high-performance framework with fine-grained observable/signal-based reactivity for building rich applications. - vobyjs/voby
Want results from more Discord servers?
Add your server