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

React Native预约App:选择日期后已预约时间按钮未置灰求助

React Native预约App:日期切换后已预约时间按钮不更新状态的修复方案

核心问题分析

  1. 参数传递错误:点击场地卡片时,传递给handleImageClick的是字符串类型的场地文档ID,但函数内部错误地尝试访问selectedFieldId?.id_lapangan属性,导致Firestore查询条件无效,无法获取对应场地的预约数据,bookingData始终为空,无法判断时间是否被预约。
  2. 日期变化未触发状态更新:切换日期后,没有重新筛选或请求对应日期的预约数据,组件无法更新时间按钮的状态。

修复步骤

1. 修复场地ID的查询参数

修改handleImageClick函数,直接使用传入的场地ID作为查询条件,同时保存当前选中的场地ID,用于后续日期切换时重新查询:

const handleImageClick = async (selectedFieldId: any) => {
  try {
    const querySnapshot = await firestore()
      .collection('booking')
      .where('id_lapangan', '==', selectedFieldId) // 移除多余的?.id_lapangan
      .get();

    const bookings: any = querySnapshot.docs.map(doc => doc.data());
    setBookingData(bookings);
    setSelectedTime(null);
    setSelectedFieldId(selectedFieldId); // 保存当前选中场地ID
    console.log('Data booking :', bookings);
  } catch (error) {
    console.log('Error fetching booking data:', error);
  }
};

2. 日期切换时重新请求对应场地的预约数据

在handleDateChange函数中添加逻辑,当日期切换且已有选中场地时,拉取该场地对应日期的预约数据(添加日期范围过滤,减少数据传输量):

const handleDateChange = async (event: any, selectedDate: any) => {
  const currentDate = selectedDate || date;
  setShowDatePicker(false);

  const selectedDateTime = moment(currentDate).tz('Asia/Singapore');
  const selectedDateOnly = selectedDateTime.format('YYYY-MM-DD');

  const today = moment().tz('Asia/Singapore');
  const normalizedCurrentDate = moment(selectedDateOnly).startOf('day');
  const normalizedToday = moment(today).tz('Asia/Singapore').startOf('day');

  if (normalizedCurrentDate.isBefore(normalizedToday)) {
    Alert.alert('Tanggal tidak valid', 'Tolong pilih tanggal yang valid');
    return;
  }

  setDate(selectedDateTime.toDate());

  // 若已选中场地,重新拉取对应日期的预约数据
  if (selectedFieldId) {
    try {
      const startOfDay = moment(selectedDateOnly).startOf('day').tz('Asia/Singapore').toDate();
      const endOfDay = moment(selectedDateOnly).endOf('day').tz('Asia/Singapore').toDate();
      const querySnapshot = await firestore()
        .collection('booking')
        .where('id_lapangan', '==', selectedFieldId)
        .where('waktu', '>=', startOfDay)
        .where('waktu', '<=', endOfDay)
        .get();

      const bookings: any = querySnapshot.docs.map(doc => doc.data());
      setBookingData(bookings);
    } catch (error) {
      console.log('Error fetching booking data on date change:', error);
    }
  }
};

3. 优化时间预约状态的判断逻辑

确保日期和小时的匹配逻辑准确处理时区,避免因格式不一致导致的匹配失败:

const isTimeBooked = bookingData.find(
  booking => {
    const bookingDate = moment(booking.waktu).tz('Asia/Singapore').format('YYYY-MM-DD');
    const selectedDateStr = moment(date).tz('Asia/Singapore').format('YYYY-MM-DD');
    const bookingHour = moment(booking.waktu).tz('Asia/Singapore').hours();
    return bookingDate === selectedDateStr && bookingHour === time.getHours();
  }
);

修改后的关键代码片段

const ScheduleScreen = () => {
  // 保留原有状态,确保selectedFieldId已定义
  const [selectedFieldId, setSelectedFieldId] = useState(null);

  // ... 其他原有函数

  const handleImageClick = async (selectedFieldId: any) => {
    try {
      const querySnapshot = await firestore()
        .collection('booking')
        .where('id_lapangan', '==', selectedFieldId)
        .get();

      const bookings: any = querySnapshot.docs.map(doc => doc.data());
      setBookingData(bookings);
      setSelectedTime(null);
      setSelectedFieldId(selectedFieldId);
      console.log('Data booking :', bookings);
    } catch (error) {
      console.log('Error fetching booking data:', error);
    }
  };

  const handleDateChange = async (event: any, selectedDate: any) => {
    const currentDate = selectedDate || date;
    setShowDatePicker(false);

    const selectedDateTime = moment(currentDate).tz('Asia/Singapore');
    const selectedDateOnly = selectedDateTime.format('YYYY-MM-DD');

    const today = moment().tz('Asia/Singapore');
    const normalizedCurrentDate = moment(selectedDateOnly).startOf('day');
    const normalizedToday = moment(today).tz('Asia/Singapore').startOf('day');

    if (normalizedCurrentDate.isBefore(normalizedToday)) {
      Alert.alert('Tanggal tidak valid', 'Tolong pilih tanggal yang valid');
      return;
    }

    setDate(selectedDateTime.toDate());

    if (selectedFieldId) {
      try {
        const startOfDay = moment(selectedDateOnly).startOf('day').tz('Asia/Singapore').toDate();
        const endOfDay = moment(selectedDateOnly).endOf('day').tz('Asia/Singapore').toDate();
        const querySnapshot = await firestore()
          .collection('booking')
          .where('id_lapangan', '==', selectedFieldId)
          .where('waktu', '>=', startOfDay)
          .where('waktu', '<=', endOfDay)
          .get();

        const bookings: any = querySnapshot.docs.map(doc => doc.data());
        setBookingData(bookings);
      } catch (error) {
        console.log('Error fetching booking data on date change:', error);
      }
    }
  };

  return (
    // ... 原有渲染结构不变
    <View style={styles.buttonContainer}>
      {Array.from(Array(4), (_, row) => (
        <View style={styles.row} key={`row_${row}`}>
          {Array.from(Array(row === 0 || row === 3 ? 3 : 4), (_, col) => {
            let index;
            if (row === 0) index = col;
            else if (row === 1) index = 3 + col;
            else if (row === 2) index = 7 + col;
            else if (row === 3) index = 11 + col;

            if (index < availableTimes.length) {
              const time = availableTimes[index];
              const isTimeBooked = bookingData.find(
                booking => {
                  const bookingDate = moment(booking.waktu).tz('Asia/Singapore').format('YYYY-MM-DD');
                  const selectedDateStr = moment(date).tz('Asia/Singapore').format('YYYY-MM-DD');
                  const bookingHour = moment(booking.waktu).tz('Asia/Singapore').hours();
                  return bookingDate === selectedDateStr && bookingHour === time.getHours();
                }
              );

              return (
                <TouchableWithoutFeedback
                  key={`button_${index}`}
                  onPress={() => setSelectedTime(time)}>
                  <View
                    style={[
                      styles.button,
                      isTimeBooked ? styles.buttonUnavailable : null,
                      selectedTime === time ? styles.buttonSelected : null
                    ]}>
                    <Text style={styles.buttonText}>
                      {time.getHours()}:00
                    </Text>
                  </View>
                </TouchableWithoutFeedback>
              );
            }
            return null;
          })}
        </View>
      ))}
    </View>
    // ... 原有渲染结构不变
  );
};

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 16:35:55