Say I have the following component, how would I iterate over and render each child to do stuff like wrapping each child with other components?
interface StuffProps {
children: `?`
}
function Stuff({ children }: StuffProps) {
// ?
}
I've tried setting children: JSX.Element
and then doing <For each={children}>... </For>
but it gives me a typescript error.
Not sure if this is right, but I may have found an answer using the children
helper function provided by solid-js.
My solution looks something like this:
import { JSX, children as useChildren } from 'solid-js';
interface StuffProps {
children: JSX.Element
}
function Stuff({ children }: StuffProps) {
const c = useChildren(() => children).toArray()
<For each={c}> ... </For>
}
If you are not going to use children in some effects, you can wrap children with some JSX element directly:
import { Component, JSXElement } from 'solid-js';
import { render } from 'solid-js/web';
const Stuff: Component<{ children: JSXElement }> = (props) => {
return (
<div><span>Wrapper:{props.children}</span></div>
)
};
const App = () => {
return (
<div>
<Stuff>
<h1>Some Title</h1>
</Stuff>
<Stuff>
<h1>Other Title</h1>
<p>Some paragraph</p>
</Stuff>
</div>
);
}
render(() => <App />, document.body);
Here we avoid destructuring props intentionally because it will remove reactivity since you will be assigning them into some local variable. Reactivity is transmitted between components through function calls. But I will ignore this rule for now for clarity.
If you are going to use props.children
with For
components you will get error because children is not guaranteed to be an array since JSX element can be any of number
| boolean
| Node
| JSX.ArrayElement
| JSX.FunctionElement
| (string & {})
| null
| undefined
.
So, you need to make sure children is an array:
import { render, } from 'solid-js/web';
import { Component, JSXElement } from 'solid-js';
const Stuff: Component<{ children: JSXElement }> = (props) => {
const children = Array.isArray(props.children) ? props.children : [props.children];
return (
<ul>
<li>{children.map(child => child)}</li>
</ul>
)
};
const App = () => {
return (
<div>
<Stuff>
<h1>Some Title</h1>
</Stuff>
<Stuff>
<h1>Other Title</h1>
<p>Some paragraph</p>
</Stuff>
</div>
);
}
render(() => <App />, document.body);
Now you can use it with For
component:
import { render, } from 'solid-js/web';
import { Component, For, JSXElement } from 'solid-js';
const Stuff: Component<{ children: JSXElement }> = (props) => {
const children = Array.isArray(props.children) ? props.children : [props.children];
return (
<ul>
<For each={children}>
{item => <li>{item}</li>}
</For>
</ul>
)
};
const App = () => {
return (
<div>
<Stuff>
<h1>Some Title</h1>
</Stuff>
<Stuff>
<h1>Other Title</h1>
<p>Some paragraph</p>
</Stuff>
</div>
);
}
render(() => <App />, document.body);
Solid provides this convenience through child
function from the main library but you will still get type error if you use them with For
component. That is because the result can be false | readonly unknown[] | null | undefined
false | readonly unknown[] | null | undefined
false | readonly unknown[] | null | undefined
but this can be fixed by using .toArray
method instead of function invocation:
import { render, } from 'solid-js/web';
import { children, Component, For, JSXElement } from 'solid-js';
const Stuff: Component<{ children: JSXElement }> = (props) => {
const resolved = children(() => props.children);
return (
<ul>
<For each={resolved.toArray()}>
{item => <li>{item}</li>}
</For>
</ul>
)
};
const App = () => {
return (
<div>
<Stuff>
<h1>Some Title</h1>
</Stuff>
<Stuff>
<h1>Other Title</h1>
<p>Some paragraph</p>
</Stuff>
</div>
);
}
render(() => <App />, document.body);
As I said, this is a convenience for accessing children inside effects. Extracting them only to wrap in another element does not much make sense since you can do that directly like because expressions are valid JSX elements:
<div>{props.children}</div>
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.