简体   繁体   English

如何使用 typescript 注释迭代 solid-js 子级

[英]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.childrenFor组件一起使用,你会得到错误,因为 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM