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

React中显示模态框时如何阻止日历组件重渲染?

问题修复:日历创建事件时跳回当前周的解决方案

问题根源

点击日历时间范围创建事件时,showModal状态变更触发CalendarComponent重渲染,而日历的当前视图日期未被持久化,导致重渲染后回到初始的当前周。

具体修复步骤

1. 持久化日历的当前视图日期

在CalendarComponent中添加状态保存当前日历显示的起始日期,确保重渲染时保持当前视图:

export default function CalendarComponent({onTimeRangeSelected}) {
  const [events, setEvents] = useState([]);
  const [showModal, setShowModal] = useState(false);
  // 新增:保存当前日历的起始日期,初始化为当前周的第一天(周一)
  const [startDate, setStartDate] = useState(DayPilot.Date.today().firstDayOfWeek(1));
  const calendarRef = useRef(null); // 补上原代码遗漏的ref定义

  const getCalendar = () => {
    return calendarRef.current.control;
  }

  useEffect(() => {
    const getEvents = async() => {
        return await pb.collection('events').getFullList();
    }
    getEvents().then(data => {
      const mappedEvents = data.map(event => ({
        id: event.id,
        start: new Date(event.start),
        end: new Date(event.end)
      }));
      setEvents(mappedEvents);
    })
  }, [])

  const createEvent = async(args) => {
    const dp = getCalendar();
    const event = await pb.collection('events').create({
      start: args.start,
      end: args.end
    });

    dp.events.add({
      id: event.id,
      start: args.start,
      end: args.end,
    });
  }

  const handleTimeRangeSelected = async (args) => {
    setShowModal(true); // 直接设为true,避免状态切换混乱
    await createEvent(args); // 等待事件创建完成,避免异步顺序问题
  }

return (
      <div style={styles.wrap}>
        <div style={styles.left}>
          <DayPilotNavigator
            selectMode={"Week"}
            weekStarts = {1}
            showMonths={2}
            skipMonths={2}
            startDate={startDate} // 绑定状态
            selectionDay={startDate} // 绑定状态
            onTimeRangeSelected={ args => {
              setStartDate(args.day); // 更新状态
              getCalendar().update({
                startDate: args.day
              });
            }}
          />
        </div>
        <div style={styles.main}>
          <DayPilotCalendar
            events={events} // 修正原代码的allEvents为state中的events
            ref={calendarRef}
            viewType = {"Week"}
            weekStarts = {1}
            headerDateFormat = {'dddd d.M.yyyy'}
            durationBarVisible = {false}
            timeRangeSelectedHandling = {"Hold"}
            onTimeRangeSelected={handleTimeRangeSelected}
            startDate={startDate} // 绑定状态,确保重渲染时保持当前视图
          />
        </div>
        {showModal && <CreateEvent showModal={showModal} setShowModal={setShowModal}></CreateEvent>}
      </div>
    );
}

2. 优化模态框组件的渲染逻辑

  • 用React.memo包裹模态框组件,减少不必要的重渲染
  • 将操作body类名的逻辑移到useEffect中,避免每次渲染执行
import React, { useState, useEffect } from 'react';

// 用React.memo包裹,仅当props变化时重渲染
export default React.memo(function CreateEvent({showModal, setShowModal}) {
    const [lesson, setLesson] = useState('');
    const [lessons, setLessons] = useState([]);

    const toggleModal = () => {
        setShowModal(!showModal);
    }

    // 移到useEffect中,仅在showModal变化时执行
    useEffect(() => {
        if (showModal) {
            document.body.classList.add('active-modal');
        } else {
            document.body.classList.remove('active-modal');
        }
        // 组件卸载时清理class
        return () => {
            document.body.classList.remove('active-modal');
        };
    }, [showModal])

    useEffect(() => {
        const getLessons = async() => {
            return await pb.collection('lessons').getFullList();
        }
        getLessons().then(data => {
            setLessons(data); 
        })
    }, [])

    const handleLessonChange = (e) => {
        setLesson(e.target.value);
    }

    return(
        <>
            {showModal && ( 
                <div className="modal">
                    <div className="overlay" onClick={toggleModal}></div>
                    <div className="modal-content">
                        <input type="button" className="close-modal" onClick={toggleModal} value="X"></input>
                        <label htmlFor="lesson">Předmět:</label>
                        <select id="lesson" value={lesson} onChange={handleLessonChange}>
                        {lessons.map((lessonItem) => { // 重命名变量避免冲突
                            return(
                                <option key={lessonItem.id} value={lessonItem.name}>{lessonItem.name}</option> // 添加key属性,符合React规范
                            )
                        })}
                        </select>
                    </div>
                </div>
            )}
        </>
    )
})

3. 额外优化点

  • 给模态框的option元素添加key属性,避免React列表渲染警告
  • 修正handleTimeRangeSelected中setShowModal的逻辑,直接设为true而非取反,避免状态切换混乱
  • 补上原代码遗漏的calendarRef定义

内容的提问来源于stack exchange,提问作者Sabby

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 06:12:02