React中插槽实现方式

默认插槽children

React 中最基本的"插槽"是通过 children 属性实现的,相当于 Vue 中的默认插槽:

// 父组件
const Card = ({ children }) => {
  return (
    
{children}
); }; // 使用 const App = () => { return (

标题

这是内容

); };

具名插槽

通过 props 传递 JSX 元素:

// 父组件
const Layout = ({ header, main, footer }) => {
  return (
    
{header}
{main}
{footer}
); }; // 使用 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;

你可能感兴趣的:(前端,javascript,react)