React.Children与React.cloneElement在函数式组件中的基本使用

654 阅读1分钟

使用场景:父子组件嵌套时的隐式交互,父组件要往子组件的【props】中入特定的属性.如受控组件.

例1:【Form】与【FormItem】.

【Form】向【FormItem的props】注入【onChange,value】等.

<Form>
    <FormItem>
        <Input/>
    </FormItem>
    <FormItem>
        <Input/>
    </FormItem>
    <FormItem>
        <Input/>
    </FormItem>
</Form>

例2:【Select】与【Option】.

【Select】向【Option的props】注入【onClick,onChange,isSelected】等.

<Select>
    <Option />
    <Option />
    <Option />
</Select>

山寨版写法实现:向子组件注入props;这种写法的问题在于:1.props的类型非正统推断得出,而是使用了as any,2.没有遵循不可变值的约定.

props.children.map((children) => {
    const childrenProps = (children as any).props;
    childrenProps.onClick = (code: string) => handleClickItem(code);
    childrenProps.isSelected = selected.includes(childrenProps.code);
    return children;
});

官方正统版写法:

第一步:父组件的children类型需要声明成FunctionComponentElement<SunProps>;

FunctionComponentElement是核心,从react中引入;

type FatherProps = {
    ...其它属性,
    children: FunctionComponentElement<SunProps>[];
};

第二步:通过两个API在父组件中,对子组件进行加工.

1.React.Children.map(参数1,参数2):参数1:就是props.children,参数2:回调函数:(child)=>newChild,其中child就是子组件的每一项,newChild就是用新的替换掉旧的.说到底,这个函数与props.children.map(item=>newItem)几乎一个效果,只是完善了一些内置兼容性检查等细节,多数时候,你使用后者同样能达到效果.

2.React.cloneElement(参数1,参数2):参数1:props.children数组中的一项,参数2:要注入(合并进)该项的props.返回值是生成一个新的child元素.

<View className={localClassName} style={props.style}>
     {React.Children.map(props.children, (child) =>
        React.cloneElement(child, {
            onClick: (code: string) => handleClickItem(code),
            isSelected: selected.includes(child.props.code),
        })
    )}
</View>