S
SolidJSā€¢2y ago
nikivi

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
nikivi
nikiviOPā€¢2y 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
nikivi
nikiviOPā€¢2y ago
GitHub
test/snake.tsx at main Ā· nikitavoloboev/test
Trying new things. Contribute to nikitavoloboev/test development by creating an account on GitHub.
nikivi
nikiviOPā€¢2y ago
GitHub
test/snake.tsx at main Ā· nikitavoloboev/test
Trying new things. Contribute to nikitavoloboev/test development by creating an account on GitHub.
nikivi
nikiviOPā€¢2y 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ā€¢2y 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
nikivi
nikiviOPā€¢2y 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?
nikivi
nikiviOPā€¢2y ago
get some type errors
nikivi
nikiviOPā€¢2y 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ā€¢2y 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
nikivi
nikiviOPā€¢2y ago
reading its docs it seems like its similar to For
thetarnav
thetarnavā€¢2y ago
And thirdly, using a store would probably be the best
nikivi
nikiviOPā€¢2y 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ā€¢2y 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ā€¢2y 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.
nikivi
nikiviOPā€¢2y ago
then moveSnake(state, setState, direction) I get this I guess
JCM
JCMā€¢2y ago
In my oppinion this has nothing to do with For vs Index
nikivi
nikiviOPā€¢2y ago
I have Q about this actually
JCM
JCMā€¢2y ago
Using a store would solve the issue
nikivi
nikiviOPā€¢2y 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ā€¢2y ago
Check if `setSnake([...newSnake]) solves the issue. By cloning the array it should always notify the subscribers
nikivi
nikiviOPā€¢2y 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ā€¢2y ago
Solid Playground
Quickly discover what the solid compiler will generate from your JSX template
JCM
JCMā€¢2y 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
nikivi
nikiviOPā€¢2y ago
example of @thetarnav is blowing my mind a bit trying to make sense of it
thetarnav
thetarnavā€¢2y 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
nikivi
nikiviOPā€¢2y ago
GitHub
test/box.tsx at main Ā· nikitavoloboev/test
Trying new things. Contribute to nikitavoloboev/test development by creating an account on GitHub.
nikivi
nikiviOPā€¢2y ago
I am now trying to
thetarnav
thetarnavā€¢2y 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
nikivi
nikiviOPā€¢2y 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ā€¢2y ago
thetarnav
thetarnavā€¢2y ago
those will be the same references
nikivi
nikiviOPā€¢2y 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ā€¢2y ago
const newValue = setSignal(p => ...)
const newValue = setSignal(p => ...)
? But I would just destructure the top-level signal values and apply the change
nikivi
nikiviOPā€¢2y ago
ok will try thank you like Big Thief too btw šŸ™‚
thetarnav
thetarnavā€¢2y ago
this is the first time I saw a function that takes both value and the setter šŸ˜„
thetarnav
thetarnavā€¢2y ago
I would never pass the setter around
nikivi
nikiviOPā€¢2y 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ā€¢2y 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
Want results from more Discord servers?
Add your server