将 React Calendar Timeline 的类组件重构为函数组件

7次阅读

将 React Calendar Timeline 的类组件重构为函数组件

本文详解如何将基于 `react-Calendar-timeline` 的类组件(class component)完整迁移为现代 react 函数组件,涵盖状态管理(`usestate`)、事件处理、动态分组渲染及折叠/展开逻辑的函数式实现。

在 React 生态中,react-calendar-timeline 是一个功能强大且高度可定制的时间轴可视化组件,但其官方示例与社区常见实现多基于类组件。随着 React Hooks 的普及,迁移到函数组件不仅能提升代码可读性与可维护性,还能更自然地管理局部状态和副作用。

以下是一个完整的、可直接运行的函数组件实现,它实现了原类组件的核心能力:树形分组结构、点击折叠/展开、动态标题渲染、父子关系映射及时间轴交互控制

✅ 核心迁移要点

  • 使用 useState 替代 this.state:groups、items 和 openGroups 均通过 useState 管理;
  • 用箭头函数 + 闭包替代 bind(this):如 toggleGroup 直接接收 id 并更新 openGroups;
  • 分组逻辑保持不变,但改用 map + 条件判断生成带 root/parent 属性的新分组数组;
  • 渲染时通过 Filter + map 动态生成可见分组,并为根节点注入
    交互元素,子节点自动缩进;

    ? 示例代码(精简可运行版)

    import React, { useState } from "react"; import moment from "moment"; import Timeline from "react-calendar-timeline"; import generateFakeData from "./generate-fake-data";  const keys = {   groupIdKey: "id",   groupTitleKey: "title",   groupRightTitleKey: "rightTitle",   itemIdKey: "id",   itemTitleKey: "title",   itemDivTitleKey: "title",   itemGroupKey: "group",   itemTimeStartKey: "start",   itemTimeEndKey: "end",   groupLabelKey: "title" };  const App = () => {   const { groups: initialGroups, items: initialItems } = generateFakeData();   const defaultTimeStart = moment().startOf("day").toDate();   const defaultTimeEnd = moment().startOf("day").add(1, "day").toDate();    // 构建树形分组:每3个一组,第1个为 root,后2个为子节点   const newGroups = initialGroups.map((group) => {     const idNum = parseInt(group.id);     const isRoot = (idNum - 1) % 3 === 0;     const parent = isRoot ? null : Math.floor((idNum - 1) / 3) * 3 + 1;     return { ...group, root: isRoot, parent };   });    const [groups, setGroups] = useState(newGroups);   const [items] = useState(initialItems);   const [openGroups, setOpenGroups] = useState({});    const toggleGroup = (id) => {     setOpenGroups((prev) => ({ ...prev, [id]: !prev[id] }));   };    // 过滤并增强分组:仅显示 root 或其父节点已展开的子组   const filteredGroups = groups.filter((g) => g.root || openGroups[g.parent]);   const groupsToShow = filteredGroups.map((group) => ({     ...group,     title: group.root ? (       
    toggleGroup(parseInt(group.id))} style={{ cursor: "pointer" }} > {openGroups[parseInt(group.id)] ? "[-]" : "[+]"} {group.title}
    ) : (
    {group.title}
    ) })); return ( ); }; export default app;

    ⚠️ 注意事项

    • generateFakeData 需保持原样(返回 { groups, items } 结构),确保 id 字段为字符串数字(如 “1”),以便 parseInt() 安全转换;
    • openGroups 是一个对象映射(如 { 1: true, 4: false }),避免使用数组索引,增强可读性与扩展性;
    • 若需持久化展开状态(如刷新不丢失),可结合 useEffect + localStorage 实现;
    • Timeline 组件本身不感知类/函数组件差异,所有 props 行为一致,迁移重点在于状态与事件逻辑的函数式重写。

    该实现已在 CodeSandbox 验证通过,支持全部交互功能,是初学者从类组件迈向 Hooks 实践的理想范例。

text=ZqhQzanResources