setStore odd creation behavior

Hey there team! Hope you are all well. I'm experiencing some very odd behaviour around stores and was wonding if I could get some input from the community. I am making a very basic to do app, just to play around a little bit with some of the primitives solid has. I'm pretty familiar with soildjs and have built several basic webapps with it so far. In my todo app I have created a store
const [tasks, setTasks] = createStore<item[]>([{ name: "Exsist", note: "" }])
const [tasks, setTasks] = createStore<item[]>([{ name: "Exsist", note: "" }])
and can update tasks happily
setTasks(task => task.name === name, "completed", completed => !completed)
setTasks(task => task.name === name, "completed", completed => !completed)
However when I try to delete a task, I get some very strange behavior
setTasks((tasks) => tasks.filter((task) => task.name !== name))
setTasks((tasks) => tasks.filter((task) => task.name !== name))
My understanding is that here the instructions are to take tasks for the current store, filter them by tasks which are not the name given, diff that against the current store, and then set the store to that new array. IE create a new store with a list of tasks equal to the current list of tasks without the ones which have this name. I think my understanding is sound. However the results when I <For> over the list and display, is that each time I delete a task, the task is deleted, however a copy of the last task in the array is created in its place. like each element is being checked and if it does not meet the filter, it is removed and the next element is being duplicated. Ultimately giving some very odd todo list behavior. If I create 5 tasks, and then delete them all, I am left with a list of 5 tasks all duplicates of the last one create. When I try to delete that, I don't get an error, just a filter which is an empty array, but not the creation of a new store that is empty. I suspect I am doing something obviously wrong, and have no doubt you have been able to see it quickly. I suspect it has something to do with working with the proxies rather then the underlying data? but am at a loss!
5 Replies
Sam Kennedy Hine
Edit1: trying to get to the bottom of this I recreated the app in the js playgroup and have a beautiful working delete function...?!? baffled! https://playground.solidjs.com/anonymous/ab166bfd-5a55-4df5-81d4-6383b6ec4141
Solid Playground
Quickly discover what the solid compiler will generate from your JSX template
Sam Kennedy Hine
Edit2: I've since added an id system so I could attempt to follow some of the resources around. No such luck unfortunately. Current best attempt at removing an elements:
setTasks((i)=>i.filter(t=>t.id !== id))
setTasks((i)=>i.filter(t=>t.id !== id))
Edit3: Finally found a work around. Based on an old request on this forum. I am absolutely sure this is not the way to do this correctly, and have no idea why this is working when nothing else would, but it does work for now. unfortunately with a very ugly type error. Would love any feedback on how to do this in a more intuitive way if anyone has any time!
const filter = tasks.findIndex(t=>t.id==id)
setTasks(produce(v=>v.splice(filter,1)))
const filter = tasks.findIndex(t=>t.id==id)
setTasks(produce(v=>v.splice(filter,1)))
Alex Lohr
Alex Lohr8mo ago
Removing an array item is still a weak point for stores. And yes, produce is the way to go.
aryzing
aryzing8mo ago
Removing an item from an array doesn't update the array reference, which is what Solid relies on to trigger reactivity. So best to just create a new array,
setTasks((tasks) => [...tasks.filter((task) => task.name !== name)])
setTasks((tasks) => [...tasks.filter((task) => task.name !== name)])
Also, in my experience, the top-most "object" in the store (which may be an array) never changes its reference, meaning you can't have reactivity associated with it. If you need reactivity with a reference to the entire array, best nest it within an object so you can overwrite its reference with the setter
const [data, setData] = createStore({items: []});
// ...
setData("items", [...values] /* <-- new array reference */);
const [data, setData] = createStore({items: []});
// ...
setData("items", [...values] /* <-- new array reference */);
Now references to data.items will be reactive https://www.solidjs.com/docs/latest/api#arrays-in-stores
Sam Kennedy Hine
Hey there team, thanks for your input, produce did work, however @aryzing suggestion to revert to old method of wrapping array in object has worked very cleanly and getting expected results. Issue must have been to do with the managling of the topline proxy and not getting proper reactivity. Would still love to understand why I was getting duplications, but that may be for another day!