S
SolidJS•3y ago
nikiv.dev

How to do nested <For

I have a signal that is array of arrays
const [grid, setGrid] = createSignal([
[1, 1, 1, 1, 1, 1, 1, 1],
[1, 0, 0, 0, 0, 0, 0, 1],
[1, 0, 0, 0, 0, 0, 0, 1],
[1, 0, 0, 0, 0, 0, 0, 1],
[1, 0, 0, 0, 0, 0, 0, 1],
[1, 0, 0, 3, 0, 0, 0, 1],
[1, 0, 0, 4, 0, 0, 0, 1],
[1, 1, 1, 1, 1, 1, 1, 1],
])
const [grid, setGrid] = createSignal([
[1, 1, 1, 1, 1, 1, 1, 1],
[1, 0, 0, 0, 0, 0, 0, 1],
[1, 0, 0, 0, 0, 0, 0, 1],
[1, 0, 0, 0, 0, 0, 0, 1],
[1, 0, 0, 0, 0, 0, 0, 1],
[1, 0, 0, 3, 0, 0, 0, 1],
[1, 0, 0, 4, 0, 0, 0, 1],
[1, 1, 1, 1, 1, 1, 1, 1],
])
I want to render it out on screen and for solid to update it. However I read https://www.solidjs.com/tutorial/flow_for and still not too sure how to do nested <For. I tried this:
return (
<main class="Main">
<div class="boxWrapper">
<For each={grid()}>
{(row, i) => (
<For each={row}>
<div>{row}</div>
</For>
)}
</For>
</div>
</main>
return (
<main class="Main">
<div class="boxWrapper">
<For each={grid()}>
{(row, i) => (
<For each={row}>
<div>{row}</div>
</For>
)}
</For>
</div>
</main>
But it doesn't work. In react it's quite simple, I just do
return (
<main class="Main">
<div class="boxWrapper">
{grid().map((row) => {
return row.map((box) => {
return <div class="box">{box}</div>
})
})}
</div>
</main>
)
return (
<main class="Main">
<div class="boxWrapper">
{grid().map((row) => {
return row.map((box) => {
return <div class="box">{box}</div>
})
})}
</div>
</main>
)
Thanks for any help.
SolidJS
Solid is a purely reactive library. It was designed from the ground up with a reactive core. It's influenced by reactive principles developed by previous libraries.
38 Replies
nikiv.dev
nikiv.devOP•3y ago
return (
<main class="Main">
<div class="boxWrapper">
<For each={grid()}>
{(row, i) => {
return (
<>
<For each={row}>
{(box) => {
return <div class="box">{box}</div>
}}
</For>
</>
)
}}
</For>
</div>
</main>
)
return (
<main class="Main">
<div class="boxWrapper">
<For each={grid()}>
{(row, i) => {
return (
<>
<For each={row}>
{(box) => {
return <div class="box">{box}</div>
}}
</For>
</>
)
}}
</For>
</div>
</main>
)
ok this works I think šŸ¤” I am not sure why the grid is not updating
nikiv.dev
nikiv.devOP•3y ago
GitHub
test/snake.tsx at main Ā· nikitavoloboev/test
Trying new things. Contribute to nikitavoloboev/test development by creating an account on GitHub.
nikiv.dev
nikiv.devOP•3y ago
GitHub
test/snake.tsx at main Ā· nikitavoloboev/test
Trying new things. Contribute to nikitavoloboev/test development by creating an account on GitHub.
nikiv.dev
nikiv.devOP•3y ago
I console logged, the values do change I can't console log inside the component function itself as it only runs once but I thought that if I render it out with jsx it would update
thetarnav
thetarnav•3y ago
imo you should use <Index> for that as the index is what's identifying the input element - not reference because changing 0 to 1 is changing the reference
nikiv.dev
nikiv.devOP•3y ago
<Index each={grid()}>
{(row) => {
return (
<>
<Index each={row}>
{(box) => {
return <div class="box">{box}</div>
}}
</Index>
</>
)
}}
</Index>
<Index each={grid()}>
{(row) => {
return (
<>
<Index each={row}>
{(box) => {
return <div class="box">{box}</div>
}}
</Index>
</>
)
}}
</Index>
something like this?
nikiv.dev
nikiv.devOP•3y ago
get some type errors
nikiv.dev
nikiv.devOP•3y ago
SolidJS
Solid is a purely reactive library. It was designed from the ground up with a reactive core. It's influenced by reactive principles developed by previous libraries.
thetarnav
thetarnav•3y ago
Also, since the two components are to be derived from a single signal - both of them need to be subscribing to it So the nested <Index> should actually reference the signal as well in the each function
nikiv.dev
nikiv.devOP•3y ago
reading its docs it seems like its similar to For
thetarnav
thetarnav•3y ago
And thirdly, using a store would probably be the best
nikiv.dev
nikiv.devOP•3y ago
I have one component though so I put both snake and grid inside one store why doesn't it work with <For though
const [state, setState] = createStore({
grid: [
[1, 1, 1, 1, 1, 1, 1, 1],
[1, 0, 0, 0, 0, 0, 0, 1],
[1, 0, 0, 0, 0, 0, 0, 1],
[1, 0, 0, 0, 0, 0, 0, 1],
[1, 0, 0, 0, 0, 0, 0, 1],
[1, 0, 0, 3, 0, 0, 0, 1],
[1, 0, 0, 4, 0, 0, 0, 1],
[1, 1, 1, 1, 1, 1, 1, 1],
],
snake: [],
})
const [state, setState] = createStore({
grid: [
[1, 1, 1, 1, 1, 1, 1, 1],
[1, 0, 0, 0, 0, 0, 0, 1],
[1, 0, 0, 0, 0, 0, 0, 1],
[1, 0, 0, 0, 0, 0, 0, 1],
[1, 0, 0, 0, 0, 0, 0, 1],
[1, 0, 0, 3, 0, 0, 0, 1],
[1, 0, 0, 4, 0, 0, 0, 1],
[1, 1, 1, 1, 1, 1, 1, 1],
],
snake: [],
})
trying it with store
JCM
JCM•3y ago
When you call newSnake, line 155, you supply the same array (although some elements are mutated). The signal doesn't change if it's assigned a value that is equal to the old value (eg. same array) You can opt out of that with the createSignal options
JCM
JCM•3y ago
SolidJS
Solid is a purely reactive library. It was designed from the ground up with a reactive core. It's influenced by reactive principles developed by previous libraries.
nikiv.dev
nikiv.devOP•3y ago
then moveSnake(state, setState, direction) I get this I guess
JCM
JCM•3y ago
In my oppinion this has nothing to do with For vs Index
nikiv.dev
nikiv.devOP•3y ago
I have Q about this actually
JCM
JCM•3y ago
Using a store would solve the issue
nikiv.dev
nikiv.devOP•3y ago
reason I creates those mutable variables is that I can't do setStates there and expect changes to be instant they are not thats quite a big change if I move it to store hope it will solve it
function moveSnake(
state: any,
setState: (state: any) => void),
direction: "up" | "down" | "left" | "right",
) {
function moveSnake(
state: any,
setState: (state: any) => void),
direction: "up" | "down" | "left" | "right",
) {
I not sure how to type store well
JCM
JCM•3y ago
Check if `setSnake([...newSnake]) solves the issue. By cloning the array it should always notify the subscribers
nikiv.dev
nikiv.devOP•3y ago
so here
newSnake = [[rowOfHead, indexOfHead], ...snake]
newSnake = [[rowOfHead, indexOfHead], ...snake]
if (snake.length > 0) {
setSnake([[rowOfHead, indexOfHead], ...snake])
} else {
setSnake([[rowOfHead, indexOfHead]])
}
if (snake.length > 0) {
setSnake([[rowOfHead, indexOfHead], ...snake])
} else {
setSnake([[rowOfHead, indexOfHead]])
}
do this?
if (snake.length > 0) {
setSnake([[rowOfHead, indexOfHead], ...snake])
} else {
setSnake([[rowOfHead, indexOfHead]])
}
console.log(snake)
if (snake.length > 0) {
setSnake([[rowOfHead, indexOfHead], ...snake])
} else {
setSnake([[rowOfHead, indexOfHead]])
}
console.log(snake)
that console log there won't be updated value and I need new value of snake later in function or here
setGrid(updatedGrid)
setSnake(newSnake)
setGrid(updatedGrid)
setSnake(newSnake)
you mean should I continue with migration to store or that won't help
thetarnav
thetarnav•3y ago
Solid Playground
Quickly discover what the solid compiler will generate from your JSX template
JCM
JCM•3y ago
You can either create a new top level array with a spread, or alternatively use { equals: false } option on the signal to ensure it the signal fires each time the setter is called, even if it's the same array. The example of @thetarnav creates a copy with slice instead of spread, but it's similar
nikiv.dev
nikiv.devOP•3y ago
example of @thetarnav is blowing my mind a bit trying to make sense of it
thetarnav
thetarnav•3y ago
The secret is that I'm always calling grid() in each place it has to track it. Since this is a single signal, and you only reference some property of it without calling it, it won't track the change. Using createStore gives you that each property access is trackable
nikiv.dev
nikiv.devOP•3y ago
GitHub
test/box.tsx at main Ā· nikitavoloboev/test
Trying new things. Contribute to nikitavoloboev/test development by creating an account on GitHub.
nikiv.dev
nikiv.devOP•3y ago
I am now trying to
thetarnav
thetarnav•3y ago
So no component gets recreated, BUT all the places that call grid() will have to reexecute on each update to check if they don't have to update. So it's diffing, just smart diffing. Using createStore will eliminate that issue as well - you subscribe to a single value directly
nikiv.dev
nikiv.devOP•3y ago
move @thetarnav code to use my functions to update without store for now if I can as that would be a big diff so if I get it right it seems I can't pass setters to my function? like my moveSnake in the end it should just update the signal value then DOM should change as signal value is updated im confused why it doesn't 😐 I checked that logic is valid if I just console log updatedGrid and newSnake at end like the grid has right values and all I will try to add things on top of @thetarnav code instead of combining
thetarnav
thetarnav•3y ago
thetarnav
thetarnav•3y ago
those will be the same references
nikiv.dev
nikiv.devOP•3y ago
ohh ok but if I don't do it and say do set things instantly how do I get current updated values inside same function
thetarnav
thetarnav•3y ago
const newValue = setSignal(p => ...)
const newValue = setSignal(p => ...)
? But I would just destructure the top-level signal values and apply the change
nikiv.dev
nikiv.devOP•3y ago
ok will try thank you like Big Thief too btw šŸ™‚
thetarnav
thetarnav•3y ago
this is the first time I saw a function that takes both value and the setter šŸ˜„
thetarnav
thetarnav•3y ago
I would never pass the setter around
nikiv.dev
nikiv.devOP•3y ago
yea it did look ugly I just thought thats how you had to do it like im coming from react that would work in react or well you can actually have the function inside component so you don't need to pass it too
thetarnav
thetarnav•3y ago
I mean I like to have a single place where the state is updated, then it gets confusing where the change actually happens, is it batched or not, idk oh I missed that ā¤ļø ngl I have yours "Inspired" playlist often on repeat

Did you find this page helpful?