React列表组件如何遍历实际HTML子元素而非返回数组的HoC组件?
问题原因
你现有代码的问题在于,props.children中传入的<ReturnSomeStuff />是一个未执行的React元素对象,不是它渲染后返回的div数组,所以直接遍历会把它当成单个节点包裹在同一个li里。
方案1(优先推荐):调整传参方式,直接传入执行后的元素数组
修改ListifyChildren用React官方提供的Children.toArray处理children,自动打平嵌套数组,同时兼容单元素、多元素、数组等各种children格式:
import { Children } from 'react'; const ListifyChildren = (props) => { // 自动打平嵌套数组,统一处理所有children格式 const flatChildren = Children.toArray(props.children); return ( <ul className="listify"> {flatChildren.map((element, idx) => ( <li key={idx} className="listify-list-item">{element}</li> ))} </ul> ); };
使用时不要把返回数组的函数写成组件标签,直接调用函数传入返回的数组即可:
<ListifyChildren> {/* 直接调用函数返回数组,不需要写为组件标签 */} {ReturnSomeStuff()} <div>Some component</div> <div>Some other component</div> </ListifyChildren>
该方案完全符合React的设计逻辑,没有额外副作用,支持所有类型的子元素。
方案2(特殊场景使用):递归渲染打平子组件
如果你的场景要求必须保留组件标签写法(比如需要给子组件传额外props),可以通过递归渲染函数组件的方式打平子元素:
import { Children, isElement } from 'react'; // 递归打平子元素,处理函数组件返回的数组 const flattenChildren = (children) => { return Children.toArray(children).flatMap((child) => { // 判断是React元素且为函数组件 if (isElement(child) && typeof child.type === 'function') { const Component = child.type; // 直接调用函数组件拿到渲染结果 const renderedContent = Component(child.props); return flattenChildren(renderedContent); } return child; }); }; const ListifyChildren = (props) => { const flatChildren = flattenChildren(props.children); return ( <ul className="listify"> {flatChildren.map((element, idx) => ( <li key={idx} className="listify-list-item">{element}</li> ))} </ul> ); };
注意:该方案仅支持无hooks、无生命周期的纯函数组件,如果子组件用到useState、useEffect等hooks,或是类组件,直接调用函数会导致React调度逻辑失效,出现异常。
内容的提问来源于stack exchange,提问作者Lafioka
相关产品推荐
相关产品推荐

