解决React Native中日期选择时重复调用getOpenHours的问题
解决方案
核心问题分析
- 原代码中
handleDateChange未更新全局的selectedDate状态,导致无法判断当前选择的日期是否和上一次一致 react-native-modern-datepicker的onSelectedChange可能在组件重渲染、日期选中状态变化时重复触发,未做拦截处理
具体修改步骤
1. 同步选中日期状态,增加重复请求拦截
修改handleDateChange函数,先格式化日期并和当前状态对比,相同则直接返回,避免重复执行请求:
const handleDateChange = async (date) => { // 格式化日期为统一格式(和状态存储格式一致) const formattedDate = date.replace(/\//g, "-"); // 对比当前选中日期,相同则直接返回,不执行后续逻辑 if (selectedDate === formattedDate) return; // 更新全局选中日期状态 setSelectedDate(formattedDate); // 转换为Date对象用于请求 const dateObj = new Date(formattedDate); const hours = await getOpeningHours(dateObj); setOpenHours(hours); setSelectedStartHour(null); setSelectedEndHour(null); setStartHour(null); setEndHour(null); };
2. 给请求结果加缓存(可选但推荐)
如果同一个日期可能被多次选中,用缓存存储已请求过的结果,避免重复发起网络请求:
// 用useRef存储缓存,避免组件重渲染时重置 const hoursCache = useRef({}); const getOpeningHours = async (date) => { // 把Date对象转为字符串作为缓存key const dateKey = date.toISOString().split("T")[0]; // 如果缓存中有结果,直接返回 if (hoursCache.current[dateKey]) { return hoursCache.current[dateKey]; } try { const response = await axios.post( `https://spacezone-backend.cyclic.app/api/booking/getOpenHours/${placeId}`, { Date: date } ); // 存入缓存 hoursCache.current[dateKey] = response.data.openHoursArray; return response.data.openHoursArray; } catch (error) { console.log(error); return []; } };
3. 修复日期显示的小问题
原代码中<Text>Selected Date is {selectedDate}</Text>因为之前没更新状态,一直显示null,现在同步状态后就能正常显示选中的日期了。
修改后的完整代码片段
const RoomDetailsPage = ({ route }) => { const [selectedDate, setSelectedDate] = useState(null); const [selectedStartHour, setSelectedStartHour] = useState(null); const [selectedEndHour, setSelectedEndHour] = useState(null); const [startHour, setStartHour] = useState(null); const [endHour, setEndHour] = useState(null); const [isDatePickerVisible, setDatePickerVisible] = useState(false); const { roomId, placeId, roomDetails } = route.params; const startDate = roomDetails.days[0].date.split("T")[0]; const endDate = roomDetails.days[roomDetails.days.length - 1].date.split("T")[0]; const [openHours, setOpenHours] = useState([]); // 缓存已请求过的日期的开放时间 const hoursCache = useRef({}); const handleDateChange = async (date) => { const formattedDate = date.replace(/\//g, "-"); // 拦截重复日期选择 if (selectedDate === formattedDate) return; setSelectedDate(formattedDate); const dateObj = new Date(formattedDate); const hours = await getOpeningHours(dateObj); setOpenHours(hours); setSelectedStartHour(null); setSelectedEndHour(null); setStartHour(null); setEndHour(null); }; const getOpeningHours = async (date) => { const dateKey = date.toISOString().split("T")[0]; if (hoursCache.current[dateKey]) { return hoursCache.current[dateKey]; } try { const response = await axios.post( `https://spacezone-backend.cyclic.app/api/booking/getOpenHours/${placeId}`, { Date: date } ); hoursCache.current[dateKey] = response.data.openHoursArray; return response.data.openHoursArray; } catch (error) { console.log(error); return []; } }; return ( <View> <View> <Text style={styles.subtitle}>Select Date</Text> <Text>Selected Date is {selectedDate}</Text> <DatePicker onSelectedChange={handleDateChange} options={{ backgroundColor: "#090C08", textHeaderColor: "#FFA25B", textDefaultColor: "#F6E7C1", selectedTextColor: "#fff", mainColor: "#F4722B", textSecondaryColor: "#D6C7A1", borderColor: "rgba(122, 146, 165, 0.1)", }} current="2023-06-01" mode="calendar" minimumDate={startDate} maximumDate={endDate} minuteInterval={30} style={{ borderRadius: 10 }} /> </View> {/* List of selectable hours */} {openHours && openHours.length > 0 ? ( <> <Text style={styles.subtitle}>Select Hours</Text> <View style={styles.hoursContainer}> {openHours.map((hour) => ( <TouchableOpacity key={hour} style={[ styles.hourCard, hour === selectedStartHour || hour === selectedEndHour ? styles.selectedHourCard : null, ]} onPress={() => handleHourPress(hour)} > <Text>{hour}:00</Text> </TouchableOpacity> ))} </View> </> ) : ( <Text>Loading open hours...</Text> )} </View> ); };
关键说明
- 日期对比拦截是核心:确保只有当日期真正变化时才执行请求和状态更新
- 缓存机制进一步优化性能:避免相同日期重复发起网络请求,减少服务器压力和用户等待时间
- 同步
selectedDate状态:既解决了重复请求的判断依据,也修复了页面上日期显示的问题
内容的提问来源于stack exchange,提问作者YoussefAdel
相关产品推荐
相关产品推荐

