Reactivity issues
Hi. I am coming back to Solid after a long hiatus for a brand new project. I have been stuck trying to solve a very annoying reactivity issue that I have.
I have an object in a signal (I do not use a store because I want it to be undefined), value of which gets passed to a component via a prop. There are also props for modifying that object. This object has an array of other objects, and I am using
Index
to render it. Whenever I remove an object from that array, its data gets "shifted" around, until I modify an attribute of that array that has an effect on rendering. Using For
fixes this issue but it introduces a plethora of other bugs, like the settings popover for that object losing focus from the text input element (because the element based on that object data is being remade, including the settings popover). I asked LLM AIs to no avail. In Vue, I'd usually fix that by assigning it a different key
value to trigger a rerender.
I am lost and confused, please point me to the right direction.34 Replies
Maybe you can share a simple reproduction on
https://playground.solidjs.com
Solid Playground
Quickly discover what the solid compiler will generate from your JSX template
Let me see if I can
I can't seem to easily reproduce the issue due to the complex amount of CSS I have, and the Solid playground doesn't seem to support dedicated CSS files.
@Madaxen86 Here is my best attempt at a reproduction. While it doesn't reproduce the exact same scenario I have in my project, it has other side effects. To reproduce the issue exactly I'd have to introduce A TON of CSS into the mix which is in this case quite overkill.
https://playground.solidjs.com/anonymous/1195067c-4cf0-4192-99f0-3e32058d3c01
I do not think I can do any better, I have a headache and I am tired.
Solid Playground
Quickly discover what the solid compiler will generate from your JSX template
If I replace the Index with For then nothing works at all. Oh my god.
maybe you want to use Key from solid primitives https://github.com/solidjs-community/solid-primitives/tree/main/packages/keyed#key
GitHub
solid-primitives/packages/keyed at main · solidjs-community/solid-...
A library of high-quality primitives that extend SolidJS reactivity. - solidjs-community/solid-primitives
This one seems to re-render EVERYTHING regardless if it was changed or not.
Or maybe I'm using the key argument incorrectly
probably the latter
Okay yeah I was using the key argument incorrectly
Okay, yeah, looks like this is going to work! Thanks!
I think the issue with using For is that you use only one signal, but mutate the array deeply
For creates a value signal for each of the rendered items, if you mutate the item object that signal will not detect it as a change.
you usually want to create signals for each value that you want to change.
so you don’t mutate objects, but only assign signals
So you're saying I need to create signals INSIDE the object itself?
yeah
thats what stores do
This would likely conflict with the origin type that I'm assigning the data to, wouldn't it?
and thats what you do when you don't use stores
yeah
you have Data and ReactiveData basically
stores solve that by pretending they are the original type
(just like refs and reactives do in vue btw)
vue has shallowRefs which are signal equivalents
In my case I want the object to be undefined, providing the editor a hint that there is no event data so it goes into date assign mode. Stores cannot be undefined and that's why I don't use them here, unless I want to check for an empty object, and checking for an empty object is... rough
you can nest the data in an object
{data: T | null}
Hm good point I guess
I was just trying to keep the codebase as concise as possible, so I am trying to avoid such bandaid solutions
But would Solid track the said nested data deeply like it usually does?
Is it smart enough to see that this is a union type that also can be nullish?
Because I fear I might run into the same caveat here
solid doesn't use types
but there should be no issue
I thought Solid uses TS under the hood? Or did I misinterpret your statement incorrectly?
it's just runtime
exactly like vue
at least the reactivity
maybe something like Key should be built-in btw 🤔 I've never needed it myself, but now I find myself writing a chrome extension that has to get what to render from another process, so necessarily references get broken, and I don't really want to throw a store at this (and my reconcile function doesn't even support matching up by "id" it seems)
I agree, those coming from Vue will find this useful
Actually now that I think about it TS just compiles to JS and doesn't even have any kinds of safeguards in runtime, so...
I would still reconcile manually and use signals
thats what I do in solid-devtools for everything
doing it manually it very much non trivial I think, one has to sort of reimplement the mapping function
generally if you use createMutable and Key you should have a very similar expirience as in vue
Speaking of solid-devtools I wanted to check it out but I could not find a firefox extension for it
there is a firefox version
pretty sure it's just called solid-devtools or "Solid Devtools"
I've never used createMutable, the store path syntax while disorienting at first is actually sufficient
yeah
just saying
because in vue you usually just do
data.value = some_json
render it with for and key and it works
solid forces you to be more explicit
but the same is possiblewhy torture yourself with setStore though
I wouldn't call it torture
Cloning the object, editing it and setting the signal to it - that's torture lol
fair
I just haven't yet explored how do Solid's mutable stores work under the hood as I never needed to use them
basically for each property a signal is created/read/written under the hood for you
But since my project focuses on UX I guess it could've made more sense to use
I presume under the hood it is a proxy object with watchers of some kind? Never used proxies in regular JS let alone in Solid
watchers? it is a proxy object that intercepts reads and writes, and a bunch of other things, but not everything necessary
In Vue you could do
watch(ref, () => {...})
to do something when the value of a ref changes, I believe an equivalent in Solid is createEffect(on(signal, () => {...}))
That's why I called them watchers
I've read up on proxies just now, looks like the image in my head was correct
I suppose that's all from me for now, thanks all
that was for sure enlightening