React组件遍历子元素的子节点报错?求正确实现方案
问题描述
我有一个可接收单个或多个子元素的组件,用法如下:
接收多个子元素的情况
<SideDataGridItem> <div id='top'> <div>A1</div> <div>B1</div> <div>C1</div> </div> <div id='bottom'> <div>A2-</div> <div>B2-</div> <div>C2-</div> </div> </SideDataGridItem>
接收单个子元素的情况
<SideDataGridItem> <div id='top'> <div>A1</div> <div>B1</div> <div>C1</div> </div> </SideDataGridItem>
我希望遍历这些子元素的子节点,最终输出不需要包含id为top或bottom的div,只需要渲染它们的子节点(比如A1、B1这类)。
失败的尝试1
import { ReactElement, Children } from 'react'; export interface PropsShape { children: ReactElement | ReactElement[]; } const SideDataGridItem = ({ children }: PropsShape): ReactElement => { const childArr = Children.toArray(children); return ( <> {childArr[0] && childArr[0].map(function (item: any, i: number) { return ( <div key={i}> {item}- {i} </div> ); })} {childArr[1] && childArr[1].map(function (item: any, i: number) { return ( <div key={i}> {item}- {i} </div> ); })} </> ); }; export { SideDataGridItem };
报错:
Property 'map' does not exist on type 'ReactChild | ReactFragment | ReactPortal'. Property 'map' does not exist on type 'string'.
失败的尝试2
import { ReactElement, Children } from 'react'; export interface PropsShape { children: ReactElement | ReactElement[]; } const SideDataGridItem = ({ children }: PropsShape): ReactElement => { const childArr = Children.toArray(children); return ( <> // map over the childArr {childArr.map(function (item: any) { // for each item inside the childArr map over them ?? expecting just 3 items not 4 or 1 { item.map(function (itemInner: any, i: number) { return ( <div key={i}> {itemInner}- {i} </div> ); }); } })} </> ); }; export { SideDataGridItem };
失败的尝试3
打印childArr后发现目标子节点在childArr[0].props.children中,尝试遍历:
{childArr[0] && childArr[0].props.children.map(function (item: any, i: number) { return ( <div key={i}> {item}- {i} </div> ); })}
报错:
Property 'props' does not exist on type 'ReactChild | ReactFragment | ReactPortal'. Property 'props' does not exist on type 'string'.
解决方案
问题核心在于TypeScript的类型限制:Children.toArray(children)返回的数组元素类型是ReactChild | ReactFragment | ReactPortal,直接访问props或调用map会因为类型不明确报错。需要先校验元素类型,再安全处理子节点。
最终实现代码:
import { ReactElement, Children, isValidElement } from 'react'; export interface PropsShape { children: ReactElement | ReactElement[]; } const SideDataGridItem = ({ children }: PropsShape): ReactElement => { const childElements = Children.toArray(children); return ( <> {childElements.map((parentChild, parentIndex) => { // 校验当前元素是否为React合法元素 if (isValidElement(parentChild)) { // 将目标子节点统一转为数组处理 const innerChildren = Children.toArray(parentChild.props.children); return innerChildren.map((item, i) => ( <div key={`${parentIndex}-${i}`}> {item}- {i} </div> )); } // 非React元素直接返回(比如文本节点) return parentChild; })} </> ); }; export { SideDataGridItem };
代码说明
- 类型校验:通过
isValidElement判断子元素是否为React元素,避免访问props时触发类型错误。 - 统一处理子节点:用
Children.toArray将每个父元素的子节点转为数组,兼容单个或多个子节点的场景。 - 唯一key:组合父元素索引与子元素索引生成唯一key,避免渲染时出现重复key警告。
这样无论组件接收单个还是多个子元素,都能正确遍历并渲染它们的子节点,且不会输出外层的top/bottom容器div。
内容的提问来源于stack exchange,提问作者Bill
相关产品推荐
相关产品推荐

