React实战:插槽模式

React中如何使用类vue的插槽模式,以及React.cloneElement

React中实现插槽模式

👉 sandbox 👈

概念

插槽:从父组件中传递一个对像给子组件,这个对象中的内容可以是组件,也可以是一段文本内容,还可以是一个事件方法

  • 父组件:定义插槽,并将插槽和插槽的输入参数传入子组件,

  • 子组件:接收插槽,并渲染/执行插槽

插槽分为匿名和具名两种模式

  • 匿名插槽:直接通过props.children传递
  • 具名插槽:在props作为参数传递(函数式组件本质上是个函数,可以做参数)

注意:插槽的使用逻辑是子组件是封装好的工具,某些部分是固定的,而某些部分是按场景区分的,我们提前知道这些部分的渲染位置,而渲染内容不一致。

例如

子组件是一个抽屉框Drawer组件,它的Header位置可能是一个控制导航的NavBar组件,也可能是一个搜索框Input组件。

这时候在上层调用Drawer时,就需要由父组件来定义Header具体是什么组件,并且将什么数据传入Header。

同时子组件Drawer中只处理共性的抽象的逻辑:渲染Header组件,并将收到的参数传入Header组件

代码

👉 sandbox 👈

渲染结果:

slot header

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

  • 0: tom
  • 1: jerry
  • 2: jake

下面的例子中想要渲染一个列表,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 />, // element
{ Title }, // props
// children
userList.map((item, idx) => <ListItem>{`${idx}: ${item}`}</ListItem>)
);
}

// List组件,有具名插槽Title和匿名插槽
export default function List(props) {
const { Title } = props;
return (
<div>
{Title ? <Title /> : null}
<ul>{props.children}</ul>
</div>
);
}

// ListItem组件,有匿名插槽
export default function ListItem(props) {
return <li>{props.children}</li>;
}

------ 本文结束 ❤ 感谢你的阅读 ------
------ 版权信息 ------

本文标题:React实战:插槽模式

文章作者:Lury

发布时间:2022年07月12日 - 23:06

最后更新:2022年07月12日 - 23:25

原始链接:https://luryzhu.github.io/2022/07/12/React/react1_slot/

许可协议:署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。