S
SolidJS•12mo ago
gubsey

Signals not updating in <For> tag

I have code that looks like this:
const [grid, updateGrid] = createSignal(new Array(10).fill([]).map(_ => new Array(10).fill(false).map(_ => Math.random() * 10 < 5)))

const flip = (x: number, y: number) => {
let val = grid();
val[y][x] = !val[y][x]
updateGrid(val)
}

return (
<table>
<tbody>
<For each={grid()}>{(row, y) => (
<tr>
<For each={row}>{(cell, x) => (
<td
class={`${cell ? "bg-green-500" : 'bg-red-500'} w-8 h-8 border border-separate`}
onclick={_ => flip(x(), y())}></td>
)}</For>
</tr>
)}</For>
</tbody>
</table>
);
const [grid, updateGrid] = createSignal(new Array(10).fill([]).map(_ => new Array(10).fill(false).map(_ => Math.random() * 10 < 5)))

const flip = (x: number, y: number) => {
let val = grid();
val[y][x] = !val[y][x]
updateGrid(val)
}

return (
<table>
<tbody>
<For each={grid()}>{(row, y) => (
<tr>
<For each={row}>{(cell, x) => (
<td
class={`${cell ? "bg-green-500" : 'bg-red-500'} w-8 h-8 border border-separate`}
onclick={_ => flip(x(), y())}></td>
)}</For>
</tr>
)}</For>
</tbody>
</table>
);
This creates a random grid of red ang green squares. I want to be able to click any square and have the color flip. With logging, I found that the grid signal is updating, but the colors aren't changing. Am I completely misunderstanding signals here?
27 Replies
REEEEE
REEEEE•12mo ago
the array is still the same technically So you can do updateGrid([...val])
gubsey
gubsey•12mo ago
? I'll try that That still didn't work
const flip = (x: number, y: number) => {
let val = grid();
val[y][x] = !val[y][x]
updateGrid([...val])
}
const flip = (x: number, y: number) => {
let val = grid();
val[y][x] = !val[y][x]
updateGrid([...val])
}
It's definitely changing grid It just isn't reflecting those changes in the render
REEEEE
REEEEE•12mo ago
hmm right, but I believe For relies on referential equality of the element. Meaning technically you're updating the same array that was initially pased Here's a quick solution, pass {equals: false} to the second paramter of createSignal createSignal(yourStuff here, {equals: false}) Optionally, use a store instead
Grahf
Grahf•12mo ago
React docs have a section just for updating arrays in state: https://react.dev/learn/updating-arrays-in-state I've used it to update my signals in Solid. It's terrible. Not sure if it will help you or not
gubsey
gubsey•12mo ago
this also didn't work I'll look into stores this worked!
Grahf
Grahf•12mo ago
what did you do lol?
gubsey
gubsey•12mo ago
changed every <For> to arr.map
Grahf
Grahf•12mo ago
nice
gubsey
gubsey•12mo ago
return (
<table>
<tbody>
{grid().map((row, y) => (
<tr>
{row.map((cell, x) => (
<td
class={`${cell ? "bg-green-500" : 'bg-red-500'} w-8 h-8 border border-separate`}
onclick={_ => flip(x, y)}></td>
))}
</tr>
))}
</tbody>
</table>
)
return (
<table>
<tbody>
{grid().map((row, y) => (
<tr>
{row.map((cell, x) => (
<td
class={`${cell ? "bg-green-500" : 'bg-red-500'} w-8 h-8 border border-separate`}
onclick={_ => flip(x, y)}></td>
))}
</tr>
))}
</tbody>
</table>
)
REEEEE
REEEEE•12mo ago
However, every update will cause it to rerender the whole grid/list
gubsey
gubsey•12mo ago
Yea that's not wrong... but none of the other method's were working...
REEEEE
REEEEE•12mo ago
Solid Playground
Quickly discover what the solid compiler will generate from your JSX template
REEEEE
REEEEE•12mo ago
Here you go
gubsey
gubsey•12mo ago
Thanks! I appreciate you guys! Any idea why a store works but a signal doesn't? also this syntax is beautiful updateGrid(y, x, p => !p)
REEEEE
REEEEE•12mo ago
Here is the signal version
REEEEE
REEEEE•12mo ago
Solid Playground
Quickly discover what the solid compiler will generate from your JSX template
REEEEE
REEEEE•12mo ago
Like I said previously, it has to do with referential equality I believe, I can't seem to remember the specifics though 🤔 But for this kind of thing I would still use a store
gubsey
gubsey•12mo ago
oh I see what you did I don't really understand referential equality, but I'm guessing it's similar to the == vs === distinction
REEEEE
REEEEE•12mo ago
Well in terms of arrays, [1, 2, 3, 4] after pushing a 5 becomes [1, 2, 3, 4, 5]. While the number of items did change, the underlying array is still the same if you know what I mean. And since that array did not change, the For doesn't update either
gubsey
gubsey•12mo ago
right yea Coming from the rust world, these equality rules are still so strange to me
REEEEE
REEEEE•12mo ago
That's kind of the general idea, it's been discussed here before but I can't remember at the moment
gubsey
gubsey•12mo ago
I miss ownership and borrowing
REEEEE
REEEEE•12mo ago
I have yet to dive into that world but I look forward to it
gubsey
gubsey•12mo ago
I wish you the best of luck. I've been building my entire backend with axum and I dread ever having to use js. You've made it much easier😅
REEEEE
REEEEE•12mo ago
Glad I could help 😄
oneiro
oneiro•12mo ago
Actually values vs. references is a thing in Rust (and probably in all languages), too. When you borrow something you access the same location in memory - the same reference. When you clone something you get a new reference. If you would compare these two by reference they would not be the same thing, as they are different locations in memory. However if you compare them by value / their contents the still could be equal. So the underlying concept is not at all js specific, but fundemantally how allocation and pointers work.
gubsey
gubsey•12mo ago
Oh yea I get that. That's the whole point though, in rust you always know when you are access by value or by reference. There is never any ambiguity. It seems like every problem I have with javascript comes from not knowing.