目录
- 一、React children 与 Vue slot 全面对比
- 二、从 Vue slot 的视角来理解 React children
- 1、Vue 的默认插槽 - 基本没有本质区别(React children)
- 2、Vue 的具名插槽 - React 使用普通 Props(React children)
- 3、Vue 的作用域插槽 - 两者都能实现子组件向插槽内容提供数据(React children)
- 三、为什么 React 不专门设计一个 Slot API?
- 四、最终总结
React 的children与 Vue 的slot,核心设计思想基本相同,都是通过组件组合(Composition),让父组件向子组件提供内容,由子组件决定这些内容的渲染位置。
但二者有一个重要区别:
Vue 将 Slot 设计成专门的模板插槽机制,而 React 没有独立的 Slot API,而是通过
children和普通 Props 传递 React 节点实现类似能力。
总得来讲,React 的children比 Vue 的slot更简约大气一些,更符合“大道至简”的路子。
一、React children 与 Vue slot 全面对比
| 对比维度 | Reactchildren/ Props | Vueslot |
|---|---|---|
| 核心定位 | 基于 Props 的组件组合机制 | 专门用于组件内容分发的插槽机制 |
| 核心思想 | 组件接收外部传入的内容,并决定其渲染位置 | 组件声明插槽位置,父组件提供插槽内容 |
| 默认插槽 | children | <slot /> |
| 具名插槽 | 普通 Props,如header、footer | <slot name="header" /> |
| 插槽内容传递 | 传递 React 节点(JSX 等) | 传递模板片段,底层以插槽函数表示 |
| 作用域插槽 | 通过 Render Props(函数 Props)实现 | 通过 Scoped Slots 实现 |
| 内容作用域 | JSX 通常在父组件的词法作用域中创建 | 插槽内容通常在父组件的模板作用域中求值 |
| 子组件向内容提供数据 | 调用函数 Props 并传入参数 | 通过<slot :data="...">暴露 Slot Props |
| 默认内容 | 通过 JS 默认值、条件判断实现 | 直接在<slot>内声明后备内容 |
| 多区域组合 | 多个 JSX Props | 多个具名 Slot |
| 类型约束 | TypeScript 定义 Props 类型 | defineSlots()等机制 |
| 灵活性 | JSX、函数和 Props 组合非常自由 | 模板语义明确,具名和作用域插槽更直观 |
| 主要特点 | 统一、灵活、偏 JavaScript 组合 | 声明式、语义清晰、偏模板组合 |
二、从 Vue slot 的视角来理解 React children
1、Vue 的默认插槽 - 基本没有本质区别(React children)
React:
functionCard({children}){return(<div className="card">{children}</div>);}<Card><h2>标题</h2><p>内容</p></Card>Vue:
<!-- Card.vue --><template><divclass="card"><slot/></div></template><!-- 使用 --><Card><h2>标题</h2><p>内容</p></Card>两者效果相同:父组件提供内容,Card组件决定内容插入的位置。
2、Vue 的具名插槽 - React 使用普通 Props(React children)
React:
functionLayout({header,footer,children}){return(<><header>{header}</header><main>{children}</main><footer>{footer}</footer></>);}<Layout header={<Header/>}footer={<Footer/>}><Content/></Layout>Vue:
<!-- Layout.vue --><template><header><slotname="header"/></header><main><slot/></main><footer><slotname="footer"/></footer></template><!-- 使用 --><Layout><template#header><Header/></template><Content/><template#footer><Footer/></template></Layout>这里 Vue 的优势是具有专门的插槽语法,而 React 直接利用 JSX 作为 JavaScript 值的能力。
3、Vue 的作用域插槽 - 两者都能实现子组件向插槽内容提供数据(React children)
这一点是最值得理解的。
- 普通插槽解决的是:父组件向子组件传递什么内容?
- 作用域插槽进一步解决:父组件提供的内容,如何使用子组件内部的数据?
React:Render Props
functionList({items,renderItem}){return(<ul>{items.map(item=>(<li key={item.id}>{renderItem(item)}</li>))}</ul>);}<List items={users}renderItem={user=>(<strong>{user.name}</strong>)}/>Vue:Scoped Slots
<!--List.vue--><template><ul><li v-for="item in items":key="item.id"><slot:item="item"/></li></ul></template><!--使用--><List:items="users"><template #default="{ item }"><strong>{{item.name}}</strong></template></List>React 通过调用函数renderItem(item)将数据交给父组件定义的渲染逻辑;Vue 通过slot props实现类似的数据传递。
React 也可以将children本身定义为函数,形成 Function as Children 模式。
三、为什么 React 不专门设计一个 Slot API?
Vue Slot 是一套专门的内容分发 API;React children 是利用通用 Props 实现内容组合的一种惯用方式。
主要是两种框架的表达方式不同:
- Vue 是模板驱动的框架:需要通过
<slot>、v-slot、#header等专门语法,表达内容的插入位置及数据关系。 - React 使用 JSX 作为 JavaScript 表达式:JSX 可以赋值给变量、通过 Props 传递,也可以由函数返回。因此,无须引入专门的 Slot 语法,也能完成内容组合。
这不代表 React 比 Vue 更先进,或者 Vue 的 Slot 是多余设计。两者只是 API 设计取向不同。
四、最终总结
| Vue | React 对应机制 |
|---|---|
默认插槽slot | children |
具名插槽slot name | JSX Props |
作用域插槽v-slot | Render Props / Function as Children |
| 插槽后备内容 | 默认值或条件渲染 |
| 动态插槽名 | 动态选择 Props 或组合结构 |
| 插槽内容复用 | JSX 变量、组件组合、渲染函数 |
如果从框架设计思想上理解:
- Vue 倾向于把组件组合能力封装成专门的模板语法;
- React 倾向于利用 JavaScript 本身的表达能力实现组件组合。