Skip to content

React 插槽设计实现方案

痛点分析

React 本身没有提供原生的插槽(Slot)机制,这导致在构建可复用的布局组件时存在以下问题:

  1. 组件结构不灵活:父组件无法精确控制子内容的渲染位置
  2. 内容分发困难:无法像 Vue 那样通过 <template v-slot> 将内容分发到指定区域
  3. 布局复用受限:创建通用布局组件时,难以定义动态内容区域

解决方案:自定义插槽机制

核心思路

reactSolt

  1. 扩展虚拟 DOM 属性

    • 在 React 元素上添加自定义 slot 属性,作为内容分发的标识符:
  2. 子元素收集与转换

    • 在父组件中获取 props.children 并转换为标准数组格式:
  3. 构建插槽映射表

    • 遍历子元素数组,创建 slot 名称与元素的映射关系:
  4. 按插槽位置渲染

    • 在组件布局中根据插槽名称精确渲染内容:
  5. 传递数据

  • 通过 cloneElement 传递数据给插槽组件,实现数据传递:
js
const useSlot = (props) => {
  let childrens = [];
  if (props.children) {
    if (Array.isArray(props.children)) {
      childrens = props.children;
    } else {
      childrens = [props.children];
    }
  }
  let slotMap = {};
  childrens.forEach((children) => {
    slotMap[children.props.slot || "default"] = children;
  });
  return slotMap;
};

function Layout(props) {
  const slot = useSlot(props);
  const userData = { title: "head" };
  return (
    <>
      {/* 传递数据给header插槽 */}
      {React.cloneElement(slots.head, { userData })}
      {slot.middle}
      {slot.tail}
      {slot.default}
    </>
  );
}

export default function AppSlot() {
  return (
    <>
      <Layout>
        <h1>默认</h1>
        <h1 slot="head" {...props}>
          头部-{props.userData.title}
        </h1>
        <h1 slot="middle">中间</h1>
        <h1 slot="tail">尾部</h1>
      </Layout>
    </>
  );
}