React 中最基本的"插槽"是通过 children 属性实现的,相当于 Vue 中的默认插槽:
// 父组件
const Card = ({ children }) => {
return (
{children}
);
};
// 使用
const App = () => {
return (
标题
这是内容
);
};
通过 props 传递 JSX 元素:
// 父组件
const Layout = ({ header, main, footer }) => {
return (
{header}
{main}
);
};
// 使用
const App = () => {
return (
网站标题}
main={主要内容区域}
footer={版权信息 © 2025}
/>
);
};
// 父组件
const DataProvider = ({ render }) => {
const [data, setData] = useState({ name: '张三', age: 25 });
return (
{render(data)}
);
};
// 使用
const App = () => {
return (
(
用户信息
姓名: {data.name}
年龄: {data.age}
)}
/>
);
};
通过传递一个属性:函数式组件
应用场景:父组件需要获取子组件的数据,如element-plus中的table组件,可以通过scope获取行数据
注:这里的render只是一个属性名,也可以通过默认插槽children实现,直接传入一个函数式组件
// 父组件
const DataProvider = ({ children }) => {
const [data, setData] = useState({ name: '张三', age: 25 });
return (
{children(data)}
);
};
// 使用
const App = () => {
return (
{(data) => (
用户信息
姓名: {data.name}
年龄: {data.age}
)}
);
};
需要明确的是:React其实并没有插槽的概念,其本质是属性prop的单向传递
因此可以将多个插槽放到一个对象中,传递子组件
// 父组件
const Dashboard = ({ slots }) => {
return (
{slots.topbar}
{slots.content}
);
};
// 使用
const App = () => {
return (
,
topbar: ,
content:
}}
/>
);
};
这里就其实有点有vue中的h函数(渲染函数)的感觉了~
方式一:props传递
const Tabs = ({ children }: { children: React.ReactNode }) => {
const [activeTab, setActiveTab] = useState(0);
// 克隆子元素并传递额外的 props
const enhancedChildren = React.Children.map(children, (child, index) => {
return React.cloneElement(child as React.ReactElement<{ title: string, children: React.ReactNode, isActive: boolean, onActivate: () => void }>, {
isActive: index === activeTab,
onActivate: () => setActiveTab(index),
});
});
return {enhancedChildren};
};
Tabs.Tab = (props: { title: string, children: React.ReactNode, isActive?: boolean, onActivate?: () => void }) => {
return (
{props.title}
{props.isActive && {props.children}}
);
};
// 使用
const App = () => {
return (
标签1的内容
标签2的内容
标签3的内容
);
};
export default App;
方式二:context
const TabsContext = React.createContext<{ activeTab: number, setActiveTab: Dispatch>} | undefined>(undefined)
// 定义Tab组件的属性类型
type TabProps = {
children: React.ReactNode;
title: string;
isActive?: boolean;
index?: number;
};
// 定义Tabs组件的类型,包含Tab属性
interface TabsComponent extends React.FC<{ children: React.ReactNode }> {
Tab: React.FC;
}
// 先定义Tabs组件
const Tabs: TabsComponent = ({ children }: { children: React.ReactNode }) => {
const [activeTab, setActiveTab] = useState(0)
return (
{
React.Children.map(children, (child, index) => {
return React.cloneElement(child as React.ReactElement, {
isActive: index === activeTab,
index: index
})
})
}
)
}
// 然后定义Tab组件作为Tabs的属性
Tabs.Tab = (props: TabProps) => {
const { activeTab, setActiveTab } = useContext(TabsContext)!
return (
setActiveTab(props.index || 0)}>
{props.title}
{props.isActive && {props.children}}
)
}
const App = () => {
return (
<>
这是标签1的内容
这是标签2的内容
这是标签3的内容
>
)
}
export default App;