You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Syncfusion React Schedule组件求助:重复渲染、数据丢失等多问题

处理Syncfusion React Schedule组件的常见问题及解决方案

针对你遇到的5个Syncfusion Schedule组件问题,逐个给出修复方案:

问题1:无法移除title/subject属性否则报错

Syncfusion Schedule默认要求事件数据包含subject字段(对应title),如果不需要显示该字段,可以:

  • 在fieldsData中保留subject映射,给事件数据设置默认空字符串
  • 或者通过CSS隐藏主题相关元素,避免报错:
.e-schedule .e-event-content .e-subject {
    display: none;
}

问题2:禁用quickInfoTemplate,改用eventClick/cellClick触发自定义编辑器

  1. 在Schedule组件中设置quickInfoTemplate={() => null}禁用默认快速信息面板
  2. 添加eventClick和cellClick事件,手动触发自定义编辑器:
const handleEventClick = (args) => {
  scheduleObj.openEditor(args.data, "Edit");
};

const handleCellClick = (args) => {
  scheduleObj.openEditor(args, "Add");
};

// 在ScheduleComponent中添加属性
eventClick={handleEventClick}
cellClick={handleCellClick}
quickInfoTemplate={() => null}

问题3:根据项目耗时自动修改结束时间

可以在actionBegin事件中拦截创建/修改动作,自动计算endTime:

const onActionBegin = (args) => {
  if (args.requestType === "eventCreate" || args.requestType === "eventChange") {
    const { startTime, hours } = args.data[0];
    if (hours) {
      args.data[0].endTime = new Date(new Date(startTime).getTime() + hours * 60 * 60 * 1000);
    }
  }
};

也可以在自定义编辑器(CustomEditorTemplate)中监听耗时输入变化,实时更新结束时间。

问题4:window.addEventListener触发上千次、无限循环

你的代码核心错误是直接调用事件处理函数(onEventCreate())而非传递函数引用,导致组件初始化时就执行函数,且错误使用window监听事件。Syncfusion Schedule本身提供官方事件回调,无需通过window绑定:

  1. 删除localEvents数组和对应的useEffect
  2. 直接在ScheduleComponent上绑定官方事件:
const onEventCreated = (args) => {
  const newEvent = args.data;
  const exists = localData.some(item => item.id === newEvent.id);
  if (exists) {
    alert("This event already exists.");
    args.cancel = true;
    return;
  }
  setLocalData(prev => [...prev, newEvent]);
};

const onEventChanged = (args) => {
  const updatedEvent = args.data;
  setLocalData(prev => prev.map(item => 
    item.id === updatedEvent.id ? updatedEvent : item
  ));
};

const onEventDeleted = (args) => {
  const deletedId = args.data[0].id;
  setLocalData(prev => prev.filter(item => item.id !== deletedId));
};

// 在ScheduleComponent中添加属性
eventCreated={onEventCreated}
eventChanged={onEventChanged}
eventDeleted={onEventDeleted}

同时删除requestData相关逻辑,直接通过事件参数获取数据即可避免无限循环。

问题5:onActionComplete无效且丢失localStorage数据

onActionComplete中使用的localData可能不是最新状态,应该在修改localData的同时同步到localStorage,或者用useEffect监听localData变化:

// 移除原有的onActionComplete,添加以下useEffect
useEffect(() => {
  if (localData.length > 0) {
    localStorage.setItem("appointments", JSON.stringify(localData));
  }
}, [localData]);

修改后的完整代码

import { ButtonComponent } from "@syncfusion/ej2-react-buttons";
import {
  Agenda,
  Day,
  Inject,
  Month,
  ScheduleComponent,
  Week,
  WorkWeek,
} from "@syncfusion/ej2-react-schedule";
import React, { useEffect, useState } from "react";
import CustomEditorTemplate from "./EditorTemplate";
import "./MainContent.css";

export default function ScheduleCalendar() {
  let scheduleObj;
  const currentView = "Month";
  const [localData, setLocalData] = useState([]);

  // 初始化从localStorage加载数据
  useEffect(() => {
    const localStorageData = localStorage.getItem("appointments")
      ? JSON.parse(localStorage.getItem("appointments"))
      : [];
    setLocalData(localStorageData);
  }, []);

  // 数据变化时同步到localStorage
  useEffect(() => {
    if (localData.length > 0) {
      localStorage.setItem("appointments", JSON.stringify(localData));
    }
  }, [localData]);

  const fieldsData = {
    id: "id",
    subject: { name: "subject" },
    startTime: { name: "startTime" },
    endTime: { name: "endTime" },
    hours: { name: "hours" },
    budgetHrs: { name: "budgetHrs" },
    description: { name: "description" },
    totalTime: { name: "totalTime" },
    project: { name: "project" },
    task: { name: "task" },
    workCode: { name: "workCode" },
    customer: { name: "customer" },
  };

  const onActionBegin = (args) => {
    // 根据耗时自动计算结束时间
    if (["eventCreate", "eventChange"].includes(args.requestType)) {
      const eventData = args.data[0];
      if (eventData.hours) {
        eventData.endTime = new Date(
          new Date(eventData.startTime).getTime() + eventData.hours * 60 * 60 * 1000
        );
      }
    }
  };

  const editorTemplate = (props) => {
    return props !== undefined ? <CustomEditorTemplate {...props} /> : <div></div>;
  };

  const handleOpenEditor = () => {
    const cellData = {
      startTime: new Date(),
      subject: "", // 添加强制需要的subject字段
    };
    scheduleObj.openEditor(cellData, "Add");
  };

  // 事件创建完成回调
  const onEventCreated = (args) => {
    const newEvent = args.data;
    const exists = localData.some(item => item.id === newEvent.id);
    if (exists) {
      alert("This event already exists.");
      args.cancel = true;
      return;
    }
    setLocalData(prev => [...prev, newEvent]);
  };

  // 事件修改完成回调
  const onEventChanged = (args) => {
    const updatedEvent = args.data;
    setLocalData(prev => prev.map(item => 
      item.id === updatedEvent.id ? updatedEvent : item
    ));
  };

  // 事件删除完成回调
  const onEventDeleted = (args) => {
    const deletedId = args.data[0].id;
    setLocalData(prev => prev.filter(item => item.id !== deletedId));
  };

  // 点击事件触发编辑
  const handleEventClick = (args) => {
    scheduleObj.openEditor(args.data, "Edit");
  };

  // 点击单元格触发添加
  const handleCellClick = (args) => {
    scheduleObj.openEditor(args, "Add");
  };

  const eventTemplate = (props) => {
    return <div className="template-wrap">{props.customer}</div>;
  };

  return (
    <ScheduleComponent
      ref={(t) => (scheduleObj = t)}
      currentView={currentView}
      eventSettings={{
        dataSource: localData,
        fields: fieldsData,
        template: eventTemplate,
      }}
      editorTemplate={editorTemplate}
      actionBegin={onActionBegin}
      eventCreated={onEventCreated}
      eventChanged={onEventChanged}
      eventDeleted={onEventDeleted}
      eventClick={handleEventClick}
      cellClick={handleCellClick}
      quickInfoTemplate={() => null} // 禁用快速信息面板
    >
      <div className="e-toolbar-items e-tbar-pos">
        <ButtonComponent
          iconCss="e-icons e-date-time"
          className="e-control e-btn"
          id="targetButton1"
          onClick={handleOpenEditor}
        />
      </div>
      <Inject services={[Day, Week, WorkWeek, Month, Agenda]} />
    </ScheduleComponent>
  );
}

内容的提问来源于stack exchange,提问作者Giovanna G. Julio

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 05:55:07