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

React预约日历项目报错:Cannot read properties of undefined (reading 'appointments')

解决「Cannot read properties of undefined (reading 'appointments')」错误及实现日期预约功能

错误根源

你遇到的错误是因为useQuery在请求未完成(loading为true)或请求失败时,data变量为undefined,此时直接访问data.appointments会触发属性读取错误。另外当前代码还存在逻辑偏差:会渲染所有预约,而非你选中日期的对应预约。

修复步骤及代码修改

1. 处理加载与错误状态

在组件渲染时优先判断loading和error状态,避免在数据未就绪时访问data:

  • 加载中显示提示文本
  • 请求失败时展示错误信息

2. 安全访问data.appointments

使用可选链操作符(?.)或多层条件判断,确保data存在后再访问appointments属性。

3. 过滤选中日期的预约

添加日期匹配逻辑,只渲染与selectedDate对应的预约项,需统一日期格式后再做对比。

修改后的完整代码

import React, { useState } from "react";
import { GET_APPOINTMENTS, CREATE_APPOINTMENT } from "../utils/mutations";
import { useMutation, useQuery } from "@apollo/client";
import Calendar from "react-calendar";

function AppointmentCalendar() {
  const { loading, error, data } = useQuery(GET_APPOINTMENTS);
  const [createAppointment] = useMutation(CREATE_APPOINTMENT, {
    // 新增:创建预约后自动重新拉取列表,更新UI
    refetchQueries: [{ query: GET_APPOINTMENTS }]
  });

  const [date, setDate] = useState(new Date());
  const [selectedDate, setSelectedDate] = useState(null);
  const [appointmentText, setAppointmentText] = useState("");

  const handleDateChange = (date) => {
    setSelectedDate(date);
  };

  const handleAddAppointment = () => {
    if (selectedDate && appointmentText.trim() !== "") {
      createAppointment({
        variables: { date: selectedDate.toISOString(), text: appointmentText },
      })
        .then(() => {
          setSelectedDate(null);
          setAppointmentText("");
        })
        .catch((error) => {
          console.error(error);
        });
    }
  };

  // 辅助函数:格式化日期为YYYY-MM-DD,用于匹配预约日期
  const formatDate = (date) => {
    return date.toISOString().split('T')[0];
  };

  // 加载状态拦截
  if (loading) return <div>加载预约数据中...</div>;
  // 错误状态拦截
  if (error) return <div>获取预约失败: {error.message}</div>;

  return (
    <div>
      <h1>预约日历</h1>
      <div>
        <Calendar onChange={handleDateChange} value={date} />
      </div>
      <div>
        {selectedDate && (
          <div>
            <h2>{selectedDate.toLocaleDateString()} 的预约</h2>
            <input
              type="text"
              placeholder="添加预约内容"
              value={appointmentText}
              onChange={(e) => setAppointmentText(e.target.value)}
            />
            <button onClick={handleAddAppointment}>添加预约</button>
            {/* 安全访问并过滤选中日期的预约 */}
            {data?.appointments?.length > 0 ? (
              <ul>
                {data.appointments
                  .filter(appt => formatDate(new Date(appt.date)) === formatDate(selectedDate))
                  .map((appointment) => (
                    <li key={appointment.id}>{appointment.text}</li>
                  ))}
              </ul>
            ) : (
              <p>当前日期暂无预约</p>
            )}
          </div>
        )}
      </div>
    </div>
  );
}

export default AppointmentCalendar;

额外优化说明

  • 新增refetchQueries配置,创建预约后自动重新拉取列表,确保UI实时同步
  • 添加日期格式化辅助函数,保证选中日期与预约日期的匹配逻辑准确
  • 当选中日期无预约时,显示友好提示文本

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 13:22:08