Understanding Solid reactivity with console.log

I'm using createMemo with a console.log inside. Can you tell me why is this console.logging all the items, when I click on one? Am I using createMemo in a wrong way? I thought only the 2 changed items would be recalculated. I created a Stackblitz + GitHub repo to undestand this better: https://stackblitz.com/~/github.com/hyperknot/solidjs-sandbox This is the line with the console.log https://github.com/hyperknot/solidjs-sandbox/blob/a19b9581595bedd7b5e7949560a7b0d0755b8fd7/src/1-simple/store/doc.js#L15
15 Replies
Chris P Bacon
Chris P Bacon6d ago
I'm still trying to decypher the code to understand why your memo is triggering for each and every click. A couple of things that I initially spot that might or might not be a cause of your bug: 1. the circular dependency of uistate.js and doc.js is either already, or will in the future, cause you problems 2. why are you calling createRoot? this is a helper from solid which in meant to initialize the reactive system, so normally you only do this once in order to 'mount' solid to the DOM. aaaaah, I see why, you are using uiStore.state.activeDocID inside of your memo. since the uistore is also a reactive store this means that your memo is tracking both the internal store of the doc itself. and also the uistore. This is also the behavior you want, because otherwise your isActive would never update. so to summarize, the reason you are seeing all the numbers being logged is because each and every Doc is answering the question if it is active or not. if you just wish to log the one or two Doc's that actually changed than you want to add a createEffect that logs the isActive memo. then you would only see the numbers that did change
bigmistqke
bigmistqke6d ago
there is a primitive for stuff like isActive: createSelector its purpose is exactly so that you don't need a memo for each isActive would look something like
const isActive = createSelector(() => store, (doc, store) => store.activeDocID === doc.uuid)
const isActive = createSelector(() => store, (doc, store) => store.activeDocID === doc.uuid)
they wrap it in a createRoot because they initialize the signals outside of the render-function/component. to prevent that cannot cleanup computations outside of ... warning
Chris P Bacon
Chris P Bacon6d ago
aaaah, gotcha
bigmistqke
bigmistqke6d ago
although iirc that warning is only there when u have computations/memos/effects
Chris P Bacon
Chris P Bacon6d ago
just for my understanding than. isn't it bad practice to create that stuff outside of the render tree? I always avoid creating top level signals and such for the same reason. or at least I think it is for the same reason
bigmistqke
bigmistqke6d ago
it's a bad practice if you use SSR because then you can accidentally create shared data between sessions but if you are client-only you can definitely use it that pattern of creating a module with a store and importing the store + actions is called a singleton in solidjs i use it all the time, it's a pretty awesome way of doing global state, no hassle with contexts and stuff this warning you can actually also just ignore if you don't need the computation to ever clean up, which would be the case with global state but this
return <div onClick={() => createEffect(...)}/>
return <div onClick={() => createEffect(...)}/>
would create a memory leak because then an effect is made (and never cleaned up) on each click
the circular dependency of uistate.js and doc.js is either already, or will in the future, cause you problems
this is very true tho and probably something you need to address
Chris P Bacon
Chris P Bacon6d ago
alright, gotcha. Guess I've never run into this due to my general aversion to global stuff. I always just opted for a context instead.
hyperknot
hyperknotOP6d ago
Thanks for all the answers! I'm still trying to wrap my head around it. What I definitely want to avoid is to create a 1000 roots. I think that's not good for performance, right? Also, I understand that createSelector exists, but I'm trying to learn createMemo first. This app is a pure Vite client side SPA. So are you saying that even though the console.log runs for all items, actually not every item is updated? I'm basically trying to understand how to minimise "re-renders" in Solid, even though it doesn't re-render. But it still updates DOM elements, doesn't it? So how can I minimise those repaints or DOM updates?
Chris P Bacon
Chris P Bacon6d ago
depends on what you mean as a rerender. like an actual render that you could make visible with devtools? or do you mean the reactivity system doing its job? because with your memo you should only get 2 items that actually rerender, the one that loses the active state, and the one that gets it but all your items run the memo itself to calculate if there is a change
hyperknot
hyperknotOP6d ago
so in this example it probably makes no sense to use any kind of advanced function. but what if it takes some computation. say it's a tree view and I need to recalculate all the subtrees. how can I make sure that only the changed items are recalculated, and not all of them? I'm also trying to get to the root of it via devtools but it seems an even more complicated subject. so basically I'm trying to learn what's happening behind the scenes, to avoid unnecessarily, potentially slow calculations
Chris P Bacon
Chris P Bacon6d ago
well, you have to calculate all of them no? the definition of isActive is if the doc's id is the same as the selectedId. so if you change the selectedId then you will need each item to check if that id is the same as theirs what I'd do in this case is probably merge the uistate and docs and utilize createSelector this would then also fix your leaky abstraction and circular references
hyperknot
hyperknotOP6d ago
I understand. But still, generally when trying to debug what can cause performance slowdowns, how should I approach it? Adding a createEffect() inside components and adding console.log? Or trying to figure out the logging component of the devtools package?
Chris P Bacon
Chris P Bacon6d ago
I always do the createEffect + console.log. But I will look into the devtools package you mentioned, I do not know of it
zulu
zulu6d ago
even the console.log you used the way you used it, uncovered work you did not expect to happen. so even if you find a nicer way to console.log only for the effected components you might not have discovered that the pattern has a wider impact.
hyperknot
hyperknotOP5d ago
OK, I'll come back when I have real life examples of work which needs memo, not just a simple equality. The biggest thing for me would be to see what is actually recalculated and why. Are there any videos out there about debugging SolidJS reactivity?

Did you find this page helpful?