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触发自定义编辑器
- 在Schedule组件中设置
quickInfoTemplate={() => null}禁用默认快速信息面板 - 添加
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绑定:
- 删除
localEvents数组和对应的useEffect - 直接在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
相关产品推荐
相关产品推荐

