React自定义tab组合组件的实例详解

 更新时间:2026年02月02日 10:08:48   作者:妙团团  
本文介绍了如何利用React的cloneElementAPI实现自定义Tab组合组件,通过将TabItem作为Tab的子组件,使用React.cloneElement方法传递props和事件处理函数,实现了父子组件状态联动,本文结合实例代码介绍的非常详细,感兴趣的朋友一起看看吧

前言

以前工作中一直使用的vue开发,最近开始写react的项目,发现好多基础都不会,导致在项目开发中踩坑。这个系列我打算,从学习中实践,直到最后完全掌握react。

自定义Tab

我们平时用的React库,Tab组件和子组件都是组合使用的,像element的React库,Tabs.Item是套在Tabs组件里面的,在React的写法里面,组件是作为children传递到父组件里面的。像这种组合的写,父组件怎么拿到子组件的状态,从而产生联动。

既然能够拿到children,那么通过children就可以监听到子组件的状态变化了。这里要用到一个React的核心api,cloneElement。这个api克隆的是组件,不是元素。

const newElement = React.cloneElement(
  element,        // 要克隆的目标元素(必须是合法的 React 元素,比如 <TabItem />)
  [props],        // 可选:要新增/覆盖的 props(会和原元素 props 合并)
  [...children]   // 可选:要替换的子元素(不传则保留原元素的子元素)
);

实现代码

通过cloneElement这个方法我们可以对组件进行处理,从而监听子组件的状态,实现联动。以下是完整代码。

import React, { useState, useCallback } from 'react';
import './custom-test-tab.css';
export const TabItem = ({ 
  children, 
  label = '', 
  value, 
  onHandleClick,
  onClick = () => { }, 
  active = false 
}) => {
  const renderClass = () => {
    return `tab-item ${active ? 'active' : ''}`;
  }
  const handleClick = (e) => {
    onHandleClick && onHandleClick(value, e); 
    onClick(e);
  };
  return (
    <div className={renderClass()} onClick={handleClick}>
      { label || children }
    </div>
  );
};
export const Tab = function ({ children, active = '', onChange = () => { } }) {
  const [activeTab, setActiveTab] = useState(active);
  // 2. 修复handleClick参数逻辑 + 补充依赖数组
  const handleClick = useCallback((value) => {
    if (value === undefined) return; // 防止空值
    setActiveTab(value);
    onChange(value);
  }, [onChange]); // 依赖数组补充onChange,避免闭包问题
  const createdTabs = () => {
    return React.Children.map(children, (child) => {
      // 安全校验:只处理TabItem类型的子组件
      if (!React.isValidElement(child) || child.type !== TabItem) {
        return child;
      }
      return React.cloneElement(child, {
        onHandleClick: handleClick, // 直接传递函数,无需包装
        active: activeTab === child.props.value,
      });
    });
  };
  return (
    <div className={'custom-test-tab'}>
      {createdTabs()}
    </div>/
  );
};
// 3. 确保Tab.Item正确挂载
Tab.Item = TabItem;
export default Tab;

使用自定义的Tab

import { useState} from "react";
import { Tab, TabItem } from "../components/custom-test-tab";
export const TestTab = () => {
  const [active, setActive] = useState('苹果');
  const onChange = (value) => {
    setActive(value);
  };
  const tabList = [
    { label: "苹果", value: "苹果", bgColor: "#FF5252" },   // 苹果 - 红色
    { label: "香蕉", value: "香蕉", bgColor: "#FFC107" },   // 香蕉 - 黄色
    { label: "橘子", value: "橘子", bgColor: "#FF9800" },   // 橘子 - 橙色
    { label: "葡萄", value: "葡萄", bgColor: "#9C27B0" },   // 葡萄 - 紫色
    { label: "凤梨", value: "凤梨", bgColor: "#4CAF50" },   // 凤梨 - 绿色
  ];
  const ContentView = ({ active }) => {
    const item = tabList.find(item => item.value === active);
    if (!item) return null;
    return (
      <div style={
        { 
          backgroundColor: item.bgColor,
          width: "100%",
          height: '200px'
         }
      }>
        {active === "苹果" && <div>苹果</div>}
        {active === "香蕉" && <div>香蕉</div>}
        {active === "橘子" && <div>橘子</div>}
        {active === "葡萄" && <div>葡萄</div>}
        {active === "凤梨" && <div>凤梨</div>}
      </div>
    );
  }; 
  return (
    <div>
      <h1>自定义组件</h1>
      <Tab onChange={onChange} active={active}>
        {
          tabList.map((item, index) => (
            <TabItem key={index} label={item.label} value={item.value}>
              {item.label}
            </TabItem>
          ))
        }
      </Tab>
      <Tab onChange={onChange} active={active}>
        {
          tabList.map((item, index) => (
            <Tab.Item key={index} label={item.label} value={item.value}>
              {item.label}
            </Tab.Item>
          ))
        }
      </Tab>
      <ContentView active={active} />
    </div>
  );
};
export default TestTab;

渲染效果

总结

证明封装的Tab组件是可以的,通过这个Tab组件的封装,不止是学会了封装这个组件,还通过这个过程学会了,组合组件封装的过程。

到此这篇关于React学习之自定义tab组合组件的文章就介绍到这了,更多相关React自定义tab组合组件内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • React实现控制减少useContext导致非必要的渲染详解

    React实现控制减少useContext导致非必要的渲染详解

    这篇文章主要介绍了React如何有效减少使用useContext导致的不必要渲染,使用useContext在改变一个数据时,是通过自己逐级查找对比改变的数据然后渲染,本文通过示例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-11-11
  • 用React实现一个简单的虚拟列表

    用React实现一个简单的虚拟列表

    虚拟列表是现在比较常用的前端渲染大数据列表的方案,目前也有很多组件库和工具库也都有对应的实现,本文将给大家介绍一下如何用React实现一个简单的虚拟列表,文中通过代码示例讲解的非常详细,需要的朋友可以参考下
    2023-12-12
  • React高频useEffect导致页面崩溃的有效解决方案

    React高频useEffect导致页面崩溃的有效解决方案

    如果你在 React 中遇到过页面卡死、高频请求、useEffect 无限触发,这篇文章会帮你一次搞懂根因,并提供可直接复制的最佳解决方案,需要的朋友可以参考下
    2025-11-11
  • React state状态属性用法讲解

    React state状态属性用法讲解

    React将组件(component)看成一个状态机(State Machines),通过其内部自定义的状态(State)和生命周期(Lifecycle)实现并与用户交互,维持组件的不同状态
    2022-11-11
  • Vite搭建React项目的方法步骤

    Vite搭建React项目的方法步骤

    这篇文章主要介绍了Vite搭建React项目的方法步骤,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-04-04
  • 解决React报错Expected `onClick` listener to be a function

    解决React报错Expected `onClick` listener to be a function

    这篇文章主要为大家介绍了React报错Expected `onClick` listener to be a function解决,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-12-12
  • react中如何使用监听

    react中如何使用监听

    在 React 中,您可以使用 addEventListener 函数来监听事件,本文通过实例代码给大家介绍react中如何使用监听,感兴趣的朋友跟随小编一起看看吧
    2023-10-10
  • webpack 2.x配置reactjs基本开发环境详解

    webpack 2.x配置reactjs基本开发环境详解

    本篇文章主要介绍了webpack 2.x配置reactjs基本开发环境详解,具有一定的参考价值,有兴趣的可以了解一下
    2017-08-08
  • react 创建单例组件的方法

    react 创建单例组件的方法

    这篇文章主要介绍了react 创建单例组件的方法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-04-04
  • React antd中setFieldsValu的简便使用示例代码

    React antd中setFieldsValu的简便使用示例代码

    form.setFieldsValue是antd Form组件中的一个方法,用于动态设置表单字段的值,它接受一个对象作为参数,对象的键是表单字段的名称,值是要设置的字段值,这篇文章主要介绍了React antd中setFieldsValu的简便使用,需要的朋友可以参考下
    2023-08-08

最新评论