React中间组件向props.children传递prop的实现及TS类型问题
实现方案
可以实现,通过React.Children.map遍历直接子元素,配合React.cloneElement注入prop即可,该逻辑只会作用于FooGiver的直接子组件,不会影响嵌套的深层组件,符合你不使用Context的需求。
完整的FooGiver实现代码如下:
import { Children, cloneElement, isValidElement } from 'react'; interface FooGiverProps { children: React.ReactNode; } const FooGiver = ({ children }: FooGiverProps) => { const foo = "bar"; return ( <> {Children.map(children, (child) => { // 仅对合法React元素注入prop,跳过文本、空值等非组件节点 if (isValidElement(child)) { return cloneElement(child, { foo } as Partial<typeof child.props>); } return child; })} </> ); }
TypeScript适配说明
默认情况下TypeScript无法感知FooGiver的prop注入逻辑,如果你将LowerLevelProps中的foo设为必填项:
interface LowerLevelProps { foo: string; // 改为必填 }
直接在FooGiver内部写<LowerLevel />时,TS会抛出「缺少必填属性foo」的错误。
如果要避免该报错,有两种常见方案:
- 保留foo为可选属性:运行时FooGiver会保证传入有效值,不会触发
No foo provided的兜底逻辑,实现成本最低 - 约束FooGiver的子组件类型:通过类型声明限定FooGiver只能接收携带foo属性的组件作为子元素,同时将foo标记为子组件调用时的可选属性,示例类型定义如下:
该方案只能做浅层校验,无法完全消除子组件的必填prop报错,适合子组件类型固定的场景。type FooAcceptComponent = React.ReactElement<{ foo?: string }>; interface FooGiverProps { children: FooAcceptComponent | FooAcceptComponent[]; }
内容的提问来源于stack exchange,提问作者Robert Townley
相关产品推荐
相关产品推荐

