[英]How to iterate over solid-js children with typescript annotations
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.我尝试设置
children: JSX.Element
然后执行<For each={children}>... </For>
但它给了我一个 typescript 错误。
Not sure if this is right, but I may have found an answer using the children
helper function provided by solid-js.不确定这是否正确,但我可能已经使用 solid-js 提供的
children
助手 function找到了答案。
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:如果你不打算在某些效果中使用孩子,你可以直接用一些 JSX 元素包装孩子:
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.在这里,我们有意避免解构 props,因为它会消除反应性,因为您会将它们分配给某个局部变量。 Reactivity is transmitted between components through function calls.
反应性通过 function 调用在组件之间传递。 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
|如果你打算将
props.children
与For
组件一起使用,你会得到错误,因为 children 不能保证是一个数组,因为 JSX 元素可以是任何number
| boolean
| boolean
| Node
| Node
| JSX.ArrayElement
| JSX.ArrayElement
.数组元素 | JSX.FunctionElement
| JSX.FunctionElement
.函数元素 | (string & {})
| (string & {})
| null
| null
| undefined
. undefined
。
So, you need to make sure children is an array:所以,你需要确保 children 是一个数组:
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:现在您可以将它与
For
组件一起使用:
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. Solid 通过主库中的
child
function 提供了这种便利,但如果将它们与For
组件一起使用,您仍然会遇到类型错误。 That is because the result can be false | readonly unknown[] | null | undefined
那是因为结果可能是
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: false | readonly unknown[] | null | undefined
但这可以通过使用.toArray
方法而不是 function 调用来修复:
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:
提取它们只是为了包装在另一个元素中没有多大意义,因为你可以直接这样做,因为表达式是有效的 JSX 元素:
<div>{props.children}</div>
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.