Is it bad to have A LOT of `createEffect` in a single component ?

Hello ! In my use case, I'm doing components to bridge classes from JavaFX to SolidJS. The classes are implemented in a way that you have a setX and getX for each property. If you setX multiple times the same object, it will reassign it and re-run everything on the JavaFX side. That's why I don't want to do everything in a single createEffect, to prevent computations in case the object assigned to X property is the same as before. For now, my code looks like this :
const StageContext: FlowComponent<{
instance: Stage
title: string
show?: boolean
}> = (props) => {
createEffect(() => {
if (props.show) props.instance.show();
else props.instance.hide();
})

createEffect(() => props.instance.setTitle(props.title));

createEffect(() => {
console.info("set children to scene");
if (props.children instanceof Scene) props.instance.setScene(props.children);
else throw new Error("The children of a StageContext must be a Scene instance.");
});

return props.instance;
};
const StageContext: FlowComponent<{
instance: Stage
title: string
show?: boolean
}> = (props) => {
createEffect(() => {
if (props.show) props.instance.show();
else props.instance.hide();
})

createEffect(() => props.instance.setTitle(props.title));

createEffect(() => {
console.info("set children to scene");
if (props.children instanceof Scene) props.instance.setScene(props.children);
else throw new Error("The children of a StageContext must be a Scene instance.");
});

return props.instance;
};
Here, there's only three properties so three createEffect, but you can easily guess how many createEffect there'll be for more bigger components with more than 10 different properties. So is it bad to have a lot of createEffect in a component ? Are there any alternative to do this that also prevents running twice a computation that was already done ?
13 Replies
bigmistqke
bigmistqke2mo ago
ye i don't think there is another way to have side-effects then using createEffect. in solid-three it also creates an effect for each prop to drive threejs. it does something like:
createEffect(() => {
for(const prop of props){
if(...){
createEffect(() => ...)
}else if(...){
createEffect(() => ...)
}else ...
}
})
createEffect(() => {
for(const prop of props){
if(...){
createEffect(() => ...)
}else if(...){
createEffect(() => ...)
}else ...
}
})
because the base-component needed to be generic.
Are there any alternative to do this that also prevents running twice a computation that was already done ?
manually caching and diffing? I know solid merges some of its effects in the jsx for performance reasons, so it's not without cost. a balance between granularity and performance
Vexcited
Vexcited2mo ago
well not sure about diffing because i would still require to do checks in the effect for all properties while only one property changed i guess that this is the best way
bigmistqke
bigmistqke2mo ago
yup
Vexcited
Vexcited2mo ago
thanks! will do that for now and wait until there's a better way to do it in the future :p
bigmistqke
bigmistqke2mo ago
the secret third option 🤫
peerreynders
peerreynders2mo ago
I think this is a symptom of code that is only interested in state when there is a transition. Solid's reactivity focuses on state, so it takes a bit more work to extract actual transition events. And it ultimately depends on the shape of your reactivity graph whether transitions cluster within the same update of the graph. If they do, comparisons could be cheaper than running multiple effect functions. But until there's a problem there's probably no reason to try something like https://playground.solidjs.com/anonymous/ead4577d-0916-4d6a-a3e6-a5ca6936ea8c And I'm sure I missed lots of edge cases.
Solid Playground
Quickly discover what the solid compiler will generate from your JSX template
Vexcited
Vexcited2mo ago
is this the secret third option ? lmfaoo that looks interesting, ill try and see what i can get from doing this i wonder how we can benchmark the two solutions what do you really mean by "it ultimately depends on the shape of your reactivity graph whether transitions cluster within the same update of the graph" i think i don't know the exact meaning of "reactivity graph" or "transitions" if i need to add more context : when I do setX it'll automatically update the property X of the element on the JavaFX side so for example, if i run label.setText("something"); it'll automatically apply the text to the element and render it it's like doing element.innerText = "something" in a DOM
peerreynders
peerreynders2mo ago
i wonder how we can benchmark the two solutions
Given the amount of explicit code it probably would be slower in most situations; hence stick with what already works. It's just an interesting pattern of when “x changes from y to z, take a snapshot of a, b, c” wrap it up with a bow and pass it on as a value.
i think i don't know the exact meaning of "reactivity graph" or "transitions"
I the playground example I had to craft the dependency graph for show, title and content to be explicit dependencies on the value() accessor so that the snapshot memo would actually detect multiple events during the same pass. If you modify that example to just independent signals that are set one after the other in frame, snapshot only ever detects one, single event on each pass, just after the source signal is set. This defeats the scheme of having only one effect because it runs after each signal set; you may as well have separate effect functions at that point. I think of signals as analog information and events as digital information. Signal state's reactivity makes sure dependent state continuously follows source state. Events on the other hand are discrete notifications of change occurring. You can derive state from events if you don't miss any of them. There are the odd occasions where I may need to do something when show goes from false to true while I couldn't care less about it going from true to false. At that point I'm more interested in the “false to true” transition on show rather than shows (continuous) state. You may be interested in this https://vsavkin.com/the-taxonomy-of-reactive-programming-d40e2e23dee4
Medium
The Taxonomy of Reactive Programming
Victor Savkin is a co-founder of nrwl.io, providing Angular consulting to enterprise teams. He was previously on the Angular core team at…
Vexcited
Vexcited2mo ago
alright so i found a cleaner solution that seems to be working pretty good on my bridge classes, i make a proxy for getX to get x() and setX to set x(value) and i just have a prop x on my component that gets spread to the bridged node instance (very inspired from gsolid implementation)
Vexcited
Vexcited2mo ago
and now im able to do pretty stuff like this ✨
Vexcited
Vexcited2mo ago
so the setText, setScene, ... are truly reactive thanks yall for the help ! don't know if i should close the post or not now
bigmistqke
bigmistqke2mo ago
so the implementation is in the bridge-class instead of the wrapper-component?
Vexcited
Vexcited2mo ago
not really, it's just to have a getter and setter that has the same name (and also same name as the prop it could get in the component) so i can just spread the props to the class from the component