理解 React children 与 Vue slot

目录

    • [一、React children 与 Vue slot 全面对比](#一、React children 与 Vue slot 全面对比)
    • [二、从 Vue slot 的视角来理解 React children](#二、从 Vue slot 的视角来理解 React children)
      • [1、Vue 的默认插槽 - 基本没有本质区别(React children)](#1、Vue 的默认插槽 - 基本没有本质区别(React children))
      • [2、Vue 的具名插槽 - React 使用普通 Props(React children)](#2、Vue 的具名插槽 - React 使用普通 Props(React children))
      • [3、Vue 的作用域插槽 - 两者都能实现子组件向插槽内容提供数据(React children)](#3、Vue 的作用域插槽 - 两者都能实现子组件向插槽内容提供数据(React children))
    • [三、为什么 React 不专门设计一个 Slot API?](#三、为什么 React 不专门设计一个 Slot API?)
    • 四、最终总结

React 的 children 与 Vue 的 slot,核心设计思想基本相同,都是通过 组件组合 (Composition),让父组件向子组件提供内容,由子组件决定这些内容的渲染位置。

但二者有一个重要区别:

Vue 将 Slot 设计成专门的模板插槽机制,而 React 没有独立的 Slot API,而是通过 children 和普通 Props 传递 React 节点实现类似能力。

总得来讲,React 的 children 比 Vue 的 slot 更简约大气一些,更符合"大道至简"的路子。

一、React children 与 Vue slot 全面对比

对比维度 React children / Props Vue slot
核心定位 基于 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:

ts 复制代码
function Card({ children }) {
  return (
    <div className="card">
      {children}
    </div>
  );
}

<Card>
  <h2>标题</h2>
  <p>内容</p>
</Card>

Vue:

html 复制代码
<!-- Card.vue -->
<template>
  <div class="card">
    <slot />
  </div>
</template>

<!-- 使用 -->
<Card>
  <h2>标题</h2>
  <p>内容</p>
</Card>

两者效果相同:父组件提供内容,Card 组件决定内容插入的位置。

2、Vue 的具名插槽 - React 使用普通 Props(React children)

React:

ts 复制代码
function Layout({
  header,
  footer,
  children
}) {
  return (
    <>
      <header>{header}</header>
      <main>{children}</main>
      <footer>{footer}</footer>
    </>
  );
}

<Layout
  header={<Header />}
  footer={<Footer />}
>
  <Content />
</Layout>

Vue:

html 复制代码
<!-- Layout.vue -->
<template>
  <header>
    <slot name="header" />
  </header>
  <main>
    <slot />
  </main>
  <footer>
    <slot name="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

ts 复制代码
function List({ 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

ts 复制代码
<!-- 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 本身的表达能力实现组件组合。
相关推荐
ghx123456ghx1 个月前
vue中slot简单用法
vue slot