React中如何使用类vue的插槽模式,以及React.cloneElement
React中实现插槽模式
👉 sandbox 👈
概念
插槽:从父组件中传递一个对像给子组件,这个对象中的内容可以是组件,也可以是一段文本内容,还可以是一个事件方法
插槽分为匿名和具名两种模式
- 匿名插槽:直接通过props.children传递
- 具名插槽:在props作为参数传递(函数式组件本质上是个函数,可以做参数)
注意:插槽的使用逻辑是子组件是封装好的工具,某些部分是固定的,而某些部分是按场景区分的,我们提前知道这些部分的渲染位置,而渲染内容不一致。
例如:
子组件是一个抽屉框Drawer组件,它的Header位置可能是一个控制导航的NavBar组件,也可能是一个搜索框Input组件。
这时候在上层调用Drawer时,就需要由父组件来定义Header具体是什么组件,并且将什么数据传入Header。
同时子组件Drawer中只处理共性的抽象的逻辑:渲染Header组件,并将收到的参数传入Header组件
代码
👉 sandbox 👈
渲染结果:
chilren Body
slot footer
具名插槽:SlotHeader,SlotFooter
匿名插槽:children的部分
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| import Child from "./Child"; export default function Parent() { const SlotHeader = (props) => <h1>{props.title}</h1>; const slotHeaderProps = { title: "slot header" }; const SlotFooter = (props) => <p>{props.content}</p>; const slotFooterProps = { content: "slot footer" }; return ( <Child SlotHeader={SlotHeader} slotHeaderProps={slotHeaderProps} SlotFooter={SlotFooter} slotFooterProps={slotFooterProps} > chilren Body </Child> ); }
export default function Child(props) { const { SlotHeader, slotHeaderProps, SlotFooter, slotFooterProps } = props; return ( <div> {SlotHeader ? <SlotHeader {...slotHeaderProps}></SlotHeader> : null} <div>{props.children}</div> {SlotFooter ? <SlotFooter {...slotFooterProps}></SlotFooter> : null} </div> ); }
|
延伸:React.cloneElement
使用React.cloneElement方法可以高效地对插槽组件注入内容
上面我们使用插槽的过程是:在上层组件决定要使用的子组件、子组件的输入参数和children
而React.cloneElement方法就提供了一种快捷地组合以上三者的方式,并返回注入完各种参数的子组件实例
参考:https://www.jianshu.com/p/2ccf0cd14388
api
1 2 3 4 5
| React.cloneElement( element, [props], [...children] )
|
element:必须是一个React组件或者原生DOM实例,例如<div />
,<List />
props:传入element的props对象
children:element的children
代码
👉 sandbox 👈
渲染结果:
user list
下面的例子中想要渲染一个列表,List和ListItem可以看作是事先定义好的工具组件,而UserList是一个业务组件,它按需地对List和ListItem进行组合
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| import React from "react"; import List from "./List"; import ListItem from "./ListItem";
export default function UserList(props) { const userList = ["tom", "jerry", "jake"]; const Title = () => <h2>user list</h2>; return React.cloneElement( <List />, { Title }, userList.map((item, idx) => <ListItem>{`${idx}: ${item}`}</ListItem>) ); }
export default function List(props) { const { Title } = props; return ( <div> {Title ? <Title /> : null} <ul>{props.children}</ul> </div> ); }
export default function ListItem(props) { return <li>{props.children}</li>; }
|